RSS 23 February 2023

6 fallas comunes en SVG y cómo solucionarlas

#svg#tutorial#espanol

Alguien me preguntó recientemente cómo debuggeo SVGs inline. Debido a que son parte del DOM, podemos inspeccionar cualquier SVG inline en cualquier navegador con las DevTools. Gracias a eso, tenemos la capacidad de analizar los elementos y descubrir cualquier problema u oportunidad potencial para optimizar el SVG.

Pero hay veces que ni siquiera podemos ver nuestros SVG. En esos casos, hay seis cosas específicas que busco cuando estoy depurando.

1. Los valores de viewBox

El viewBox es un punto común de confusión cuando se trabaja con SVG. Está técnicamente bien usar SVG inline sin él, pero perderíamos uno de sus beneficios más significativos: escalar con el contenedor. Al mismo tiempo, puede ser contraproducente cuando se configura de forma incorrecta, generando un recorte no deseado.

Los elementos están ahí cuando están clipeados, solo que están en una parte del sistema de coordenadas que no vemos. Si abriéramos el archivo en algún programa de edición de gráficos, se vería algo así:

Captura de pantalla de SVG abierto en Illustrator.

¿La forma más fácil de arreglar esto? Agregar overflow="visible" al SVG, ya sea en nuestra hoja de estilo, inline en el atributo de estilo o directamente como un atributo de presentación SVG. Pero si también aplicamos un color de fondo al SVG o si tenemos otros elementos a su alrededor, las cosas pueden verse un poco mal. En este caso, la mejor opción será editar viewBox para mostrar esa parte del sistema de coordenadas que estaba oculta:

Demostración aplicando `overflow="hidden"` y editando `viewBox`.

Hay algunos puntos adicionales sobre el viewBox que vale la pena mencionar mientras estamos en el tema:

¿Cómo funciona el viewBox?

SVG es un lienzo infinito, pero podemos controlar lo que vemos y cómo lo vemos a través del viewport y el viewBox.

El viewport es un marco de ventana en un canvas infinito. Sus dimensiones se definen por atributos width y heigh, o en CSS con las propiedades de width y heigh correspondientes. Podemos especificar cualquier unidad de longitud que queramos, pero si proporcionamos números sin unidades, por defecto serán equivalentes a píxeles.

El viewBox está definido por cuatro valores. Los dos primeros son el punto de partida en la esquina superior izquierda (valores x e y, se permiten números negativos). Edito estos valores para reencuadrar la imagen. Los dos últimos son el ancho y la altura del sistema de coordenadas dentro de la ventana gráfica — aquí es donde podemos editar la escala de la cuadrícula (que abordaremos en la sección sobre Zoom).

Acá hay un ejemplo simplificado que muestra el viewBox SVG y los atributos de width y height establecidos en <svg> :

<svg viewBox="0 0 700 700" width="700" height="700">
  <!-- etc. -->
</svg>

Reencuandre

Así que esto:

<svg viewBox="0 0 700 700">

…equivale a esto:

<svg viewBox="comienzo-eje-x comienzo-eje-y ancho alto">

El viewport (o ventana) que vemos comienza donde se encuentran 0 en el eje x y 0 en el eje y.

Cambiando esto:

<svg viewBox="0 0 700 700">

…a esto:

<svg viewBox="300 200 700 700">

…el ancho y la altura siguen siendo los mismos (700 unidades cada uno), pero el inicio del sistema de coordenadas ahora está en el punto 300 en el eje x y 200 en el eje y.

En el siguiente video, agrego un <circle> rojo al SVG con su centro en el punto 300 en el eje x y 200 en el eje y. Se puede observar cómo al cambiar las coordenadas de viewBox a los mismos valores, también cambia la ubicación del círculo en la esquina superior izquierda del marco, mientras que el tamaño representado del SVG sigue siendo el mismo (700 × 700). Todo lo que hice fue “reencuadrar” los elementos con viewBox.

Zoom

Podemos cambiar los dos últimos valores dentro de viewBox para acercar o alejar la imagen. Cuanto mayores sean los valores, más unidades SVG se agregan para que quepan en el viewport, lo que da como resultado una imagen más pequeña. Si queremos mantener una proporción de 1: 1, el ancho y la altura de nuestro viewBox deben coincidir con los valores de ancho y alto de nuestro viewport.

Veamos qué sucede en Illustrator cuando cambiamos estos parámetros. El artwork es igual al viewport que está representada por un cuadrado blanco de 700px. Todo lo demás fuera de esa área es nuestro canvas SVG infinito y queda recortada por default.

La Figura 1 a continuación muestra un punto azul en 900 en eleje x y 900 en el eje y. Si cambio los dos últimos valores de viewBox de 700 a 900 así:

<svg viewBox="300 200 900 900" width="700" height="700">

… entonces el punto azul vuelve a estar casi completamente a la vista, como se ve en la Figura 2 a continuación. Nuestra imagen se redujo porque aumentamos los valores de viewBox, pero las dimensiones reales de ancho y alto del SVG se mantuvieron iguales, y el punto azul volvió a acercarse al área sin recortar.

Figure 1.
Figure 2.

Hay un cuadrado rosa como evidencia de cómo la cuadrícula se escala para ajustarse a la ventana gráfica: la unidad se vuelve más pequeña y más líneas de cuadrícula encajan en la misma área del viewport. Dejo un Pen acá abajo para jugar con los mismos valores y ver ese trabajo en acción:

2. Width y height ausentes

Otra cosa común que miro al depurar SVG en línea es si el archivo contiene los atributos de ancho o alto. Esto no es gran cosa en muchos casos, a menos que el SVG esté dentro de un contenedor con position absolute o un contenedor flex (ya que Safari calcula el valor de ancho de SVG con 0px en lugar de auto). Excluir el width o el height en estos casos nos impide ver la imagen completa, como podemos ver al abrir esta demostración de CodePen y compararla en Chrome, Safari y Firefox.

Chrome, Safari and Firefox.

¿La solución? Agregar un width o height, ya sea como un atributo de presentación, inline en el atributo de estilo o en CSS. Evitar usar height sólo, especialmente cuando está configurado al 100% o en auto. Otra solución es declarar los valores right y left. Se puede jugar con el siguiente Pen y combinar las diferentes opciones.

3. Colores de fill and stroke involuntarios

También puede ser que estemos aplicando color a la etiqueta <svg>, ya sea un estilo inline o proveniente de CSS. Eso está bien, pero podría haber otros valores de color a lo largo del código interno o estilos que entren en conflicto con el conjunto de colores en el <svg>, causando que las partes sean invisibles.

Es por eso que tiendo a buscar los atributos de fill y stroke en el código del SVG y los elimino. El siguiente video muestra un SVG que tiene estilos en CSS con un fill rojo. Hay un par de instancias en la que partes del SVG se pintan de blanco directamente en el código; las eliminé para revelar las piezas que faltan.

4. IDs faltantes

Este puede parecer súper obvio, pero es sorprendente la frecuencia con la que lo veo surgir. Digamos que creamos un archivo SVG en Illustrator y fuimos muy diligentes en nombrar nuestras capas para que obtengan IDs en el código al exportar el archivo. Y digamos que planeamos estilear ese SVG en CSS conectando con estos IDs.

Esa es una buena manera de hacer las cosas. Pero hay muchas ocasiones en las que he visto el mismo archivo SVG exportado por segunda vez a la misma ubicación y los IDs son diferentes, generalmente al copiar/pegar los vectores directamente. Tal vez se agregó una nueva capa, o se cambió el nombre de una de las existentes o algo así. Cualquiera que sea el caso, las reglas de CSS ya no coinciden con los IDs del código SVG, lo que hace que el SVG se presente de manera diferente a lo esperado.

Pegando el archivo de Illustrator exportado a SVG en SVGOMG.

En archivos SVG de gran tamaño, puede que nos resulte difícil encontrar esos IDs. Este es un buen momento para abrir DevTools, inspeccionar la parte del gráfico que no funciona y ver si esos IDs aún coinciden o cambiaron su nombre con alguna versión _1_ por ejemplo.

5. Checklist para clipping y masking

Si encuentro un SVG recortado inesperadamente pero el viewBox funciona bien, normalmente busco en el CSS las propiedades de clip-path o mask que podrían interferir con la imagen. Es tentador seguir mirando el código inline, pero es bueno recordar que el estilo de un SVG podría estar ocurriendo en otro lugar.

El recorte y el enmascaramiento de CSS nos permiten “ocultar” partes de una imagen o elemento. En SVG, <clipPath> es una operación vectorial que corta partes de una imagen sin resultados intermedios. La etiqueta <mask> es una operación de píxeles que permite transparencia, efectos de semitransparencia y bordes borrosos.

Esta es una pequeña checklist para depurar casos en los que están involucrados el clip-path y/o mask:

  • Asegurarse de que el clipping path (o mask) y el gráfico se superpongan entre sí. Las partes superpuestas son las que se muestran.
  • Si hay un path complejo que no se cruza con nuestro gráfico, internar aplicar transformaciones hasta que coincidan.
  • Todavía se puede inspeccionar el código interno con DevTools aunque <clipPath> o <mask> no se renderizen, podemos ver su caja.
  • Copiar el código dentro del <clipPath> o <mask> y pegarlo antes de cerrar la etiqueta </svg>. Luego agregar un fill a esas formas y verificar las coordenadas y dimensiones del SVG. Si aún no se ve la imagen, intentar agregar overflow="visible" a la etiqueta <svg>.
  • Verificar que se use un ID único para <clipPath> o <mask>, y que el mismo ID se aplique a las formas o grupo de formas que están recortadas o enmascaradas. Un ID que no coincida romperá la apariencia.
  • Comprobar si hay errores tipográficos en el código entre las etiquetas <clipPath> o <mask>.
  • fill, stroke, opacity o algunos otros estilos aplicados a elementos dentro de <clipPath> son inútiles — la única parte útil es la geometría de la región de relleno de esos elementos. Es por eso que si usamos un <polyline> se comportará como un <polygon> y si usamos una <line> no se verá ningún efecto de recorte.
  • Si no se ve la imagen después de aplicar una <mask>, hay que asegurarse de que el relleno del contenido de la máscara no sea completamente negro. La luminancia del elemento de la máscara determina la opacidad del gráfico final. Podremos ver a través de las partes más brillantes y las partes más oscuras ocultarán el contenido de la imagen.

En este Pen se puede jugar con elementos enmascarados y recortados.

6. Namespaces

¿Sabías que SVG es un lenguaje de markup basado en XML? ¡Bueno, lo es! El namespace para SVG se establece en el atributo xmlns:

<svg xmlns="http://www.w3.org/2000/svg">
  <!-- etc. -->
</svg>

Hay mucho que saber sobre los namespaces en XML y MDN tiene una gran introducción al respecto. Basta con decir que el namespace proporciona contexto al navegador, informándole que el marcado es específico de SVG. La idea es que los namespaces ayuden a evitar conflictos cuando hay más de un tipo de XML en el mismo archivo, como SVG y XHTML. Este es un problema mucho menos común en los navegadores modernos, pero podría ayudar a explicar los problemas de renderizado de un SVG en navegadores más antiguos o navegadores como Gecko que son estrictos al definir tipos de documentos y namespaces.

La especificación SVG 2 no requiere namespaces cuando se utiliza la sintaxis HTML. Pero es crucial si la compatibilidad con los navegadores anteriores es una prioridad, en esos casos no está de más agregarlo. De esa forma, cuando se define el atributo xmlns del elemento <html>, no entrará en conflicto en esos casos excepcionales.

<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
  <body>
    <svg xmlns="http://www.w3.org/2000/svg" width="700px" height="700px">
      <!-- etc. -->
    </svg>
  </body>
</html>

Esto también es cierto cuando se usa SVG inline en CSS, como cuando lo usamos de background-image. En el siguiente ejemplo, aparece un icono de checkmark en el input después de una validación exitosa. Así es como se ve el CSS:

textarea:valid {
 background: white url('data:image/svg+xml,\
    <svg xmlns="http://www.w3.org/2000/svg" width="26" height="26">\
    <circle cx="13" cy="13" r="13" fill="%23abedd8"/>\
    <path fill="none" stroke="white" stroke-width="2" d="M5 15.2l5 5 10-12"/>\
    </svg>') no-repeat 98% 5px;
}

Cuando eliminamos el namespace dentro del SVG en la propiedad de background, la imagen desaparece:

Otro prefijo de namespace común es xlink:href. Lo usamos mucho cuando hacemos referencia a otras partes del SVG como: patterns, filtros, animaciones o gradientes. La recomendación es comenzar a reemplazarlo con href ya que el otro está en desuso desde SVG 2, pero puede haber problemas de compatibilidad con navegadores más antiguos. En ese caso, podemos usar ambos. Solo hay que recordar incluir el namespace xmlns:xlink=”http://www.w3.org/1999/xlink" si todavía vamos a usar xlink:href.

¡Seguir aprendiendo SVG!

Espero que estos consejos te ayuden a ahorrar mucho tiempo si te encuentras con problemas de renderizado de SVG inline. Estas son algunas de las cosas que busco. Tal vez tengas otras diferentes — si es así, ¡dímelo en los comentarios!

La conclusión es que vale la pena tener al menos una comprensión básica de las diversas formas en que se puede usar SVG. CodePen Challenges a menudo incorpora SVG y ofrece buenas prácticas. Aquí hay algunos recursos más para subir de nivel:

Hay otras personas más que sugiero seguir por la cantidad de conocimiento e información que comparten relacionada con SVG:

Este artículo se publicó por primera vez en CSS-Tricks. Gracias a las ediciones de Geoff Graham

Let's stay in touch.

mbeldi@gmail.com