YAYU/BLOG

Frontend is cool

Animacion de trazo en SVG

CSS nos permite hacer cosas increibles pero hay ocasiones en las que por más que lo intentemos no hay una manera de replicar cierto tipo de efectos usando sólo CSS o simplemente es demasiado trabajo hacerlo. Para mucho de esos casos, lo mejor es usar svg. En este caso, veremos como replicar el efecto de que estamos dibujando un trazo usando un SVG.

Paths en SVG

En SVG, los caminos que se dibujan son definidos usando la etiqueta path.

<path fill="#fffff" d=" M250, 500 C388.071187,
  500 500, 388.071187 500, 250 C500,
  111.928813 388.071187, 2.84217094e-14 250,
  2.84217094e-14 C111.928813,
  2.84217094e-14 2.84217094e-14,
  111.928813 2.84217094e-14, 250 C2.84217094e-14,
  388.071187 111.928813, 500 250, 500 Z"
></path>

El atributo d de especifica la forma del trazo y fill nos dice de que color será el trazo. Si bien cambiar el fill no es problema pues usa un formato estandar para colores, d es más complicado y por lo general su contenido es auto-generado por Illustrator, Inkscape, Sketch o cualquier otra herramienta que uses para crear el SVG.

dasharray y dashoffset

Para generar el efecto que queremos, usaremos dos propiedades de path: stroke-dasharray y dashoffset.

stroke-dasharray nos dice si el trazo debe ser discontinuo, y que tanto espacio debe haber entre cada parte del trazo.

stroke-dashoffset especifica que tanto se debe desplazar el inicio del patron que creamos con stroke-dashoarray.

Puedes probar ambas propiedades aqui:

Ahora que viste como funciona intenta poner ambos sliders al máximo, y disminiye gradualmente el dashoffset. Si realizas esto deberias obtener un efecto como este:

Y con sólo esas dos propiedades tenemos el efecto deseado.

Ahora que sabes como crear ese efecto de trazado, veamos un par de ejemplos de cómo puedes aplicarlo.

Animaciones ciclicas

Usando css podemos utilizar @keyframes para crear una animación que se repita infinitamente. Por ejemplo, aquí tenemos un SVG con un trazo con circulos.

Usando stroke-dasharray y stroke-dashoffset podemos crear un efecto de carga.

svg path {
  stroke-dasharray: 493 493;
  animation: 1500ms loading-animation linear infinite;
}

@keyframes loading-animation {
  from { stroke-dashoffset: 0; }
  to { stroke-dashoffset: 1000; }
}

Simplemente ponemos dasharray a un numero que genere suficiente espacio entre trazos (como 493) y le decimos a css que anime el offset desde 0 hasta 1000. Con esto, podemos generar un efecto de carga:

Animaciones en eventos.

Por supuesto, la mayoría de las animaciones en una aplicación no son ciclicas, sino que se ejecutan sólo como respuesta a una interacción del usuario. Por ejemplo, mostrar una confirmación:

La manera en que animamos esto es con javascript:

var path = document.getElementById('check');
var button = document.getElementById('button');

button.addEventListener('click', function() {
  // Reset
  path.style.transition = 'none';
  path.style.transitionDelay = '0';
  path.style.strokeDashoffset = 500;

  // Reflow
  path.getBoundingClientRect();

  // Animación
  path.style.transition = 'stroke-dashoffset 300ms cubic-bezier(0.07,-0.01, 1, 0.07)';
  path.style.transitionDelay = '300ms';
  path.style.strokeDashoffset = 0;
})

Lo que hacemos en esta interacción es escuchar el boton y cuando el usuario haga click ejecutamos la animación.

La manera en que animamos esto es mediante 3 pasos:

  1. Reseteamos la animación, para asegurarnos de que la secuencia sea animada completamente.
path.style.transition = 'none';
path.style.transitionDelay = '0';
path.style.strokeDashoffset = 500;
  1. Forzamos al navegador a que haga un "reflow", es decir, realice el calculo del "layout" y aplique los estilos que especificamos antes. En este caso, nos aprovechamos de que el metodo getBoundingClientRect() forza esto, así que lo ejecutamos para que el navegador aplique los cambios.
  path.getBoundingClientRect();
  1. Agregamos la animación.
path.style.transition = 'stroke-dashoffset 300ms cubic-bezier(0.07,-0.01, 1, 0.07)';
path.style.transitionDelay = '300ms';
path.style.strokeDashoffset = 0;

Aquí podemos ver la animación en acción.

NOTA: Cabe aclar que sólo ocupamos realizar el reflow porque queremos realizar un reinicio antes de ejecutar la animación. Si no realizaramos el reflow antes de la animación, la parte de la animación sobreescribiria los valores iniciales y nunca se reiniciría de la animación. Aqui un ejemplo de esto (intenta presionar el boton más de una vez):


Y eso es todo! Ahora puedes animar SVGs ya sea con JS o con sólo CSS y crear animaciones geniales de manera nativa y sin tantos problemas.

Como siempre, los ejemplos de este post están disponible en github para cualquier duda que tengas o mejora que quieras agregar, ¡así que no dudes en hacerlo!