Saltar al contenido

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.

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:

HTML
<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:

HTML
<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:

HTML
<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:

HTML
<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.