Tres modelos de gráfico: canvas, SVG y CSS
Distinguir los tres motores que la plataforma web ofrece para dibujar, entender qué modelo de datos usa cada uno y por qué esa diferencia decide casi todo lo demás.
La web no tiene un sistema de gráficos: tiene tres, y no compiten. CSS pinta cajas que el motor de layout ya colocó, SVG mantiene un árbol de formas vivo dentro del DOM, y el canvas 2D te entrega una rejilla de píxeles y una brocha. Elegir mal entre ellos no produce un error, produce un proyecto que funciona durante seis semanas y luego se atasca en un muro que no se puede rodear.
- Describir el modelo de datos de CSS, SVG y canvas, y decir qué guarda cada uno.
- Explicar por qué el modo retenido y el modo inmediato no son estilos sino arquitecturas distintas.
- Situar un problema gráfico concreto en el modelo que le corresponde antes de escribir código.
- Reconocer los tres muros clásicos contra los que choca cada modelo.
Qué guarda cada modelo
La pregunta que separa los tres motores no es “¿qué puede dibujar?” —los tres pueden dibujar un círculo rojo— sino “¿qué recuerda el navegador después de dibujarlo?”. La respuesta cambia el coste de cada operación posterior, y con ella la arquitectura completa de tu aplicación.
CSS recuerda cajas. El motor construye un árbol de cajas a partir del DOM, resuelve tamaños y posiciones con los algoritmos de layout, y después pinta cada caja con las propiedades de fondo, borde, sombra, filtro y transformación que le correspondan. Todo lo que CSS dibuja está anclado a un elemento del documento, hereda su geometría del layout y participa en el modelo de eventos sin que tú hagas nada. Esa es su virtud y su límite: no puedes dibujar algo que no sea una caja, y la caja la decide el layout, no tú.
SVG recuerda formas. Un <circle> es un nodo del DOM, con sus atributos, sus estilos calculados, su árbol de accesibilidad y sus listeners. Si cambias su atributo r, el navegador vuelve a rasterizar la escena por ti. No hay que redibujar nada a mano porque el navegador conserva la descripción geométrica completa y la reproyecta cada vez que hace falta. A esto se le llama modo retenido: la escena está retenida en una estructura de datos que el sistema gráfico posee.
El canvas 2D no recuerda nada. Tiene un búfer de píxeles y un contexto con un puñado de variables de estado. Cuando llamas a ctx.fill(), el navegador modifica píxeles y olvida inmediatamente por qué los modificó. No hay ningún objeto “círculo” al que puedas cambiarle el radio, porque nunca hubo un círculo: hubo una llamada que dejó un rastro de color. A esto se le llama modo inmediato, y no es un detalle de la API sino la decisión de diseño de la que se derivan todas las demás.
flowchart TB raiz[Grafico 2D en la web] --> css[CSS] raiz --> svg[SVG] raiz --> canvas[Canvas 2D] css --> cssq[Cajas colocadas por el layout] svg --> svgq[Arbol de formas retenido en el DOM] canvas --> canq[Rejilla de pixeles en modo inmediato] cssq --> cssu[Interfaz decoracion transiciones] svgq --> svgu[Iconos diagramas datos con pocos elementos] canq --> canu[Miles de elementos pintura y video] style raiz fill:#cba6f7,color:#11111b style css fill:#89b4fa,color:#11111b style svg fill:#a6e3a1,color:#11111b style canvas fill:#fab387,color:#11111b style cssq fill:#94e2d5,color:#11111b style svgq fill:#94e2d5,color:#11111b style canq fill:#94e2d5,color:#11111b style cssu fill:#f9e2af,color:#11111b style svgu fill:#f9e2af,color:#11111b style canu fill:#f9e2af,color:#11111b
El mismo círculo, tres veces
Nada aclara tanto la diferencia como escribir la misma figura en los tres modelos y mirar qué queda vivo después.
<!-- CSS: la forma es una caja con border-radius -->
<div class="bolita"></div>
<style>
.bolita { width: 80px; height: 80px; border-radius: 50%; background: #f38ba8; }
</style>
<!-- SVG: la forma es un nodo del DOM -->
<svg width="120" height="120" viewBox="0 0 120 120">
<circle cx="60" cy="60" r="40" fill="#a6e3a1" />
</svg>
<script>
// El nodo sigue existiendo. Cambiarlo basta: el navegador redibuja.
document.querySelector('circle').setAttribute('r', 20);
</script>
<!-- Canvas: la forma es el efecto de una llamada, y desaparece como concepto -->
<canvas id="c" width="120" height="120"></canvas>
<script>
const ctx = document.getElementById('c').getContext('2d');
ctx.fillStyle = '#89b4fa';
ctx.beginPath();
ctx.arc(60, 60, 40, 0, Math.PI * 2);
ctx.fill();
// Para "cambiar el radio" hay que borrar y volver a dibujarlo todo.
ctx.clearRect(0, 0, 120, 120);
ctx.beginPath();
ctx.arc(60, 60, 20, 0, Math.PI * 2);
ctx.fill();
</script>
Los tres producen píxeles indistinguibles. La diferencia aparece en la línea siguiente. En CSS y en SVG, modificar el círculo es una operación local sobre un objeto que existe; el navegador se encarga de la consecuencia visual y del repintado mínimo. En canvas, “modificar el círculo” no es una operación posible: solo puedes reconstruir el fotograma entero. Si tu escena tiene ocho elementos eso da igual. Si tiene ochenta mil, es precisamente lo que quieres, porque reconstruir ochenta mil rectángulos en un búfer plano es mucho más barato que mantener ochenta mil nodos del DOM con su estilo calculado, su caja y su árbol de accesibilidad.
Todo el mundo llega al canvas pensando que la ausencia de objetos es una carencia que habrá que compensar con una librería. Es al revés: es el precio explícito de un trato. El navegador te dice “yo no guardo nada, y a cambio no pago nada por guardarlo”. Cada nodo SVG cuesta memoria, cuesta estilo calculado en cada invalidación, cuesta un nodo en el árbol de accesibilidad y cuesta una entrada en el hit testing del compositor. El canvas cuesta ancho×alto×4 bytes y ni un byte más, tenga una figura o cien mil. Cuando eliges canvas estás firmando que tú vas a mantener el modelo de la escena, que tú vas a decidir qué se redibuja, y que tú vas a implementar el hit testing y la accesibilidad. Los proyectos que fracasan con canvas casi nunca fracasan por la API de dibujo: fracasan porque nadie escribió ese modelo de escena y seis meses después hay diecisiete variables sueltas haciendo de estado global. Lo que la librería de turno te vende no es “canvas más fácil”: es el modo retenido reimplementado encima del inmediato.
Los tres muros
Cada modelo tiene un muro contra el que choca, y los tres son predecibles.
CSS choca contra la forma arbitraria. Mientras necesites rectángulos, círculos, degradados y sombras, CSS es imbatible porque el navegador lo acelera, lo anima en el compositor y lo hace accesible gratis. En cuanto necesitas una polilínea con datos, una curva que responde a un cálculo o un recorte que no es una elipse, empiezas a apilar pseudoelementos y clip-path con polígonos generados a mano, y ese es el aviso de que estás en el modelo equivocado.
SVG choca contra el número de elementos. No hay una cifra mágica, porque depende del dispositivo y de con qué frecuencia cambian, pero el orden de magnitud es claro: unos pocos miles de nodos que se actualizan cada fotograma bastan para hundir el hilo principal en cualquier portátil. El coste no está en rasterizar las formas, está en mantener el DOM: recalcular estilo, invalidar layout y reconstruir el árbol de pintura para miles de nodos sesenta veces por segundo.
El canvas choca contra todo lo que el DOM te daba gratis. Accesibilidad, selección de texto, búsqueda en la página, zoom del navegador con nitidez, impresión vectorial, inspección en las herramientas de desarrollo, eventos por elemento. Ninguna de esas cosas existe dentro de un canvas, y varias de ellas —la accesibilidad, sobre todo— no se pueden recuperar del todo por mucho código que escribas.
Cómo se usa este mapa
En la práctica el mapa se recorre con tres preguntas encadenadas, y en este orden.
| Pregunta | Si la respuesta es sí | Modelo |
|---|---|---|
| ¿La forma es una caja o casi, y va anclada a un elemento? | Quédate en CSS | CSS |
| ¿Los elementos son pocos, semánticos y hay que interactuar con ellos uno a uno? | Usa SVG | SVG |
| ¿Hay miles de elementos, o pintura libre, o un fotograma que se reconstruye entero? | Usa canvas | Canvas |
El orden importa porque los tres modelos no cuestan lo mismo en mantenimiento. CSS es el más barato de escribir y el más caro de forzar; canvas es el más caro de escribir y el que menos se rompe cuando el volumen crece. Empezar por el más barato que resuelva el problema es una regla que envejece bien.
Y hay una cuarta respuesta que la tabla no recoge: los tres a la vez. Un mapa interactivo real dibuja las teselas en canvas, los marcadores clicables en SVG encima y el panel de controles en CSS. No hay ninguna regla que te obligue a elegir uno solo, y las interfaces gráficas serias de la web casi nunca lo hacen.