wandres.dev
FORMAS SVG · El catálogo de elementos

Cuándo usar una forma y cuándo bajar a path

El criterio real para elegir entre los elementos de forma y el path: animabilidad, selectores CSS, peso, morfología y lo que se rompe al convertir una cosa en la otra.

⏱ 17 min

Todo lo que dibujan rect, circle, ellipse, line, polyline y polygon se puede dibujar con path. Eso hace que la pregunta «cuándo usar cada uno» parezca una cuestión de gusto, y no lo es: la elección cambia lo que puedes animar, lo que puedes seleccionar desde CSS, cuánto pesa el fichero y qué se rompe cuando una herramienta de optimización decide convertirlo por ti. Hay un criterio, y es bastante duro.

🎯 Al terminar esta lección sabrás
  • Traducir cada forma nativa a su path equivalente y comprobar la equivalencia visual.
  • Enumerar las cuatro capacidades que se pierden al convertir una forma en path.
  • Aplicar el criterio de decisión a casos concretos de un gráfico y de un icono.
  • Anticipar qué rompe una conversión automática hecha por una herramienta de exportación.

Las equivalencias exactas

Antes de decidir conviene tener las traducciones delante, porque son mecánicas y aclaran de dónde vienen las diferencias.

Un line es una línea abierta de dos puntos:

<line x1="10" y1="20" x2="90" y2="60" />
<path d="M 10 20 L 90 60" />

Una polyline es lo mismo con más puntos; un polygon añade el cierre:

<polyline points="10,10 50,40 90,10" />
<path d="M 10 10 L 50 40 L 90 10" />

<polygon  points="10,10 50,40 90,10" />
<path d="M 10 10 L 50 40 L 90 10 Z" />

Un rect sin radios son cuatro segmentos y un cierre. Con radios, cuatro segmentos y cuatro arcos:

<rect x="10" y="10" width="80" height="50" />
<path d="M 10 10 H 90 V 60 H 10 Z" />

<rect x="10" y="10" width="80" height="50" rx="8" />
<path d="M 18 10 H 82 A 8 8 0 0 1 90 18
         V 52 A 8 8 0 0 1 82 60
         H 18 A 8 8 0 0 1 10 52
         V 18 A 8 8 0 0 1 18 10 Z" />

Y un circle, dos semicírculos, porque un solo arco cuyo punto de inicio coincide con el de fin es degenerado y se descarta:

<circle cx="50" cy="50" r="40" />
<path d="M 10 50 A 40 40 0 1 0 90 50 A 40 40 0 1 0 10 50 Z" />

Fíjate en cuánto crece la cadena en los dos últimos casos. Un rectángulo redondeado pasa de 55 caracteres a más de 130. Un círculo, de 35 a 70. Esa es una de las cuatro pérdidas.

Lo que se pierde al convertir

Uno: las propiedades de geometría. x, y, width, height, cx, cy, r, rx, ry son atributos numéricos independientes. Los puedes leer, escribir y, en los motores que exponen las propiedades de geometría como propiedades CSS, transicionar. Un path tiene un único atributo d que es una cadena: para mover un vértice hay que regenerar la cadena entera. Animar width de un rect es una línea; animar el ancho de un path rectangular es reconstruir cuatro comandos.

Dos: los selectores CSS. rect { fill: var(--barra); } deja de aplicar en cuanto alguien convierte los rectángulos a paths. Es un fallo silencioso: no hay error, simplemente el color no cambia. Si tu CSS depende del nombre del elemento, la conversión es una bomba de relojería. La defensa es usar clases en vez de selectores de tipo, y es una buena costumbre por otras razones.

Tres: la legibilidad y la diferencia en control de versiones. Un SVG generado por servidor donde las barras son rect produce diffs legibles. Con paths, cualquier cambio de un valor reescribe una cadena larga y el diff no dice nada.

Cuatro: la exactitud del rasterizado en las cónicas. Como se vio en circle y ellipse, un circle se rasteriza como cónica exacta; su versión con arcos también, porque A describe arcos elípticos de verdad. Pero muchas herramientas no convierten a arcos sino a cuatro cúbicas de Bézier, que son una aproximación con un error del orden de dos diezmilésimas del radio. Da igual en pantalla y no da igual si haces geometría computacional encima.

Lo que se gana

La lista del otro lado es más corta pero pesa mucho.

El morphing. Interpolar entre dos formas exige que ambas tengan la misma estructura de comandos. Un rect no se puede interpolar con un circle porque son elementos distintos; dos path con la misma secuencia de comandos sí. Cualquier animación de transformación de forma pasa por normalizar todo a path con el mismo número de segmentos.

La geometría que no cabe en una forma. Radios por esquina, agujeros, subrutas múltiples, curvas suaves, cualquier cosa que un diseñador dibuje con la pluma. En cuanto la forma deja de ser primitiva, path es la única opción.

Los métodos de geometría en JavaScript. getTotalLength(), getPointAtLength(), isPointInFill() e isPointInStroke() viven en SVGGeometryElement, así que en los motores actuales están disponibles en todas las formas, no solo en path. Pero getPointAtLength() sobre un rect te da un punto del perímetro rectangular, y eso rara vez es lo que quieres; el recorrido controlado (un objeto siguiendo una trayectoria) se hace sobre un path que has diseñado para ser recorrido.

El relleno con reglas. fill-rule con nonzero o evenodd solo tiene efecto cuando hay subrutas que se solapan, y eso solo ocurre en path y en polygon autointersecante. Un donut (círculo con agujero) es un path de dos subrutas con sentidos de giro opuestos, y no hay forma primitiva que lo haga.

El criterio

Con todo eso encima de la mesa, el criterio se puede escribir en una tabla.

Situación Elección Motivo
Barra de un gráfico rect Se anima height, se selecciona por tipo, diff legible
Punto de dispersión circle Menos bytes, r animable, centro natural
Línea de serie temporal path con L o curvas Una sola cadena para n puntos, y admite curvatura
Área bajo una curva path cerrado con Z La polyline no cierra y el polygon no admite curvas
Rejilla de ejes line o un path con varias subrutas Pocas líneas, line; muchas, un path con M/H repetidos
Icono de la biblioteca de diseño path Viene así de la herramienta y no vale la pena tocarlo
Forma que se va a interpolar path normalizado El morphing exige estructuras compatibles
Cápsula, píldora, badge rect con rx grande Se adapta al tamaño sin recalcular nada

La regla resumida: usa la forma primitiva mientras la primitiva describa exactamente lo que quieres, y baja a path en el momento en que necesites algo que la primitiva no tiene. No conviertas por gusto ni por uniformidad.

Las herramientas convierten sin preguntar, y hay que saberlo

Figma exporta círculos como <circle> cuando la capa sigue siendo una elipse pura, y como <path> en cuanto le has aplicado una operación booleana, un recorte o un borde con esquinas modificadas. Illustrator convierte casi todo a <path> si la forma ha pasado por el buscatrazos. Y el plugin convertShapeToPath de SVGO, que forma parte del preset por defecto, convierte rect, line, polyline y polygon a path sin avisar; los círculos y elipses solo si activas explícitamente convertArcs. Consecuencia práctica: si tu pipeline optimiza los SVG y tu CSS apunta a rect, el estilo funciona en desarrollo y desaparece en producción. Esto no se detecta con tests unitarios ni con el linter. Se detecta mirando el fichero optimizado, o no se detecta. Fija la configuración de SVGO en el repositorio, apunta con clases en lugar de con tipos de elemento, y revisa el resultado la primera vez.

⚔️ Reto práctico

Coge un icono cualquiera de tu proyecto que venga como path. Identifica si alguna de sus subrutas es en realidad un rectángulo o un círculo, y reescríbela como forma primitiva. Mide el peso antes y después, y después pásalo por Brotli para ver si la diferencia sobrevive a la compresión. El resultado te dirá si la micro-optimización de formas merece la pena en tu caso o si es ruido.