Saltar al contenido

Dónde vive cada modelo en el pipeline del navegador

Seguir el recorrido de un píxel desde el DOM hasta la pantalla y ver en qué etapa exacta se inserta CSS, SVG y canvas, para entender qué coste paga cada uno.

Las etapas y qué produce cada una

El navegador convierte documento en píxeles siguiendo siempre las mismas etapas, y cada una consume lo que produjo la anterior.

Estilo. Para cada elemento del DOM se resuelve el valor calculado de todas las propiedades CSS. La entrada es el DOM más las hojas de estilo; la salida es un valor por propiedad y por elemento.

Layout. Con esos valores se construye el árbol de cajas y se resuelve la geometría: qué tamaño tiene cada caja y en qué posición del documento cae. La salida es geometría, no color.

Pintura. Cada caja se convierte en una lista de operaciones de dibujo —rellena este rectángulo, traza este borde, dibuja este texto— en el orden de apilamiento correcto. Ojo: pintar no es rasterizar todavía; es grabar qué habría que rasterizar.

Rasterización. Esa lista de operaciones se ejecuta y produce mapas de bits, normalmente por capas y a menudo en la GPU.

Composición. Las capas rasterizadas se combinan en la imagen final aplicando transformaciones y opacidades de capa. Esta es la etapa que puede ejecutarse sin tocar el hilo principal, y por eso animar transform y opacity es barato.

Dónde entra cada modelo

CSS participa en todas las etapas. Una propiedad de fondo se resuelve en estilo, condiciona la caja en layout, se graba en pintura y se rasteriza. Por eso una animación de width es cara —invalida layout, pintura y rasterización— y una de transform es barata: solo toca composición.

SVG participa en casi todas, con una particularidad. Los elementos SVG están en el DOM y reciben estilo como cualquier otro elemento, pero no participan en el layout de flujo del documento: dentro del elemento raíz <svg> la posición no la decide el flujo sino los atributos de coordenadas y el sistema de coordenadas de usuario. El elemento <svg> externo sí es una caja normal que el layout coloca; su interior es un universo de coordenadas propio. La consecuencia práctica es que mutar el atributo cx de un círculo no dispara un reflow del documento entero, pero sí invalida la geometría y la pintura de ese subárbol SVG.

El canvas participa en una sola. Para el motor de estilo y layout, un <canvas> es un elemento reemplazado igual que una <img>: tiene un tamaño intrínseco, ocupa una caja, y su contenido es opaco. Ninguna regla CSS del documento puede afectar a lo que hay dibujado dentro, porque el contenido no es un árbol de elementos: es un mapa de bits que tú produjiste. Cuando llega la etapa de pintura, el navegador simplemente copia ese búfer en la posición que le tocó.

Qué se deduce del diagrama

Del sitio por donde entra cada modelo salen consecuencias que después parecen reglas sueltas y no lo son.

El CSS del documento no puede estilar el interior de un canvas. No es una restricción de seguridad ni un olvido: es que no hay nada que estilar. No hay elementos, no hay valores calculados, no hay cascada. Si quieres que el canvas respete el tema oscuro tienes que leer tú el valor y usarlo al dibujar.

JS
// Leer un token del tema y usarlo dentro del canvasconst raiz = getComputedStyle(document.documentElement);ctx.fillStyle = raiz.getPropertyValue('--acento').trim() || '#89b4fa';ctx.fillRect(10, 10, 100, 40);

El canvas no dispara layout al dibujar. Puedes ejecutar diez mil operaciones de dibujo sin que el navegador recalcule ni un estilo. Ese es el ahorro real. Lo que sí cuesta es cambiar el tamaño del búfer, porque eso sí cambia el tamaño intrínseco del elemento reemplazado y puede afectar al layout del documento.

El zoom del navegador se comporta distinto en cada modelo. Al hacer zoom, CSS y SVG se rasterizan de nuevo a la nueva escala y salen nítidos, porque el navegador conserva la descripción vectorial. El canvas no: su búfer tiene el tamaño que le diste y al ampliarlo se interpola. Eso es lo que produce el canvas borroso, y el remedio pasa por detectar el cambio de escala y reconstruir el búfer.

Las herramientas de desarrollo son ciegas dentro del canvas. El inspector muestra el árbol del DOM. Dentro de un canvas no hay árbol, así que no hay nada que inspeccionar más allá del elemento en sí. Depurar canvas es depurar tu código, no el documento.

Un experimento que lo enseña

La forma más directa de ver la diferencia de coste es medir dónde se va el tiempo en cada modelo con la misma carga. Este fragmento crea mil nodos SVG y los mueve, y hace lo equivalente en canvas; ejecútalo con el panel de rendimiento abierto y compara qué barras aparecen.

HTML
<div id="a"></div><canvas id="b" width="600" height="400"></canvas><script>  const N = 1000;  const puntos = Array.from({ length: N }, () => ({    x: Math.random() * 600, y: Math.random() * 400,    vx: (Math.random() - 0.5) * 2, vy: (Math.random() - 0.5) * 2,  }));  // Version SVG: N nodos, N mutaciones de atributo por fotograma  const ns = 'http://www.w3.org/2000/svg';  const svg = document.createElementNS(ns, 'svg');  svg.setAttribute('width', 600); svg.setAttribute('height', 400);  const nodos = puntos.map(() => {    const c = document.createElementNS(ns, 'circle');    c.setAttribute('r', 2); c.setAttribute('fill', '#a6e3a1');    svg.appendChild(c); return c;  });  document.getElementById('a').appendChild(svg);  // Version canvas: 1 elemento, N llamadas de dibujo por fotograma  const ctx = document.getElementById('b').getContext('2d');  function paso() {    for (const p of puntos) {      p.x += p.vx; p.y += p.vy;      if (p.x < 0 || p.x > 600) p.vx *= -1;      if (p.y < 0 || p.y > 400) p.vy *= -1;    }    nodos.forEach((n, i) => {      n.setAttribute('cx', puntos[i].x.toFixed(1));      n.setAttribute('cy', puntos[i].y.toFixed(1));    });    ctx.clearRect(0, 0, 600, 400);    ctx.fillStyle = '#89b4fa';    for (const p of puntos) {      ctx.beginPath();      ctx.arc(p.x, p.y, 2, 0, Math.PI * 2);      ctx.fill();    }    requestAnimationFrame(paso);  }  paso();</script>

En el perfil verás que el trabajo del SVG aparece repartido entre estilo, layout y pintura, mientras que el del canvas es una única barra de ejecución de script seguida de rasterización. No es que uno sea “mejor”: es que el trabajo cae en sitios distintos, y saber en cuál cae es lo que te permite optimizarlo.