Firma en la línea de puntos: Animar tu propia firma SVG
Spanish (Español) translation by Eva Collados Pascual (you can also view the original English article)
Animar el trazo de un SVG es perfecto para simular la escritura a mano. En el transcurso de dos tutoriales vamos a usar la animación CSS para hacer que una firma parezca estar realmente manuscrita, como si estuvieras firmando la página tú mismo.
Esto es lo que vamos a construir:
1. Archivo SVG
Antes de sumergirnos en cualquier código, vamos a necesitar una versión SVG de tu firma. No importa qué software utilices para hacerlo, pero trata de mantener las líneas y curvas lo más suaves posible para lograr el mejor efecto.
Aquí está la mía, que puedes ver cómo se dibuja mediante tres trazados independientes:









Asegúrate de que la mesa de trabajo esté recortada ajustándose perfectamente a la firma y, a continuación, guarda el archivo en formato SVG.
2. Ordenar el código SVG
Si abres el archivo en un editor de código verás la estructura XML del archivo SVG. Dependiendo de la aplicación que utilizases para diseñarla, además de cómo la guardases o exportases, tendrás un elemento <svg> con alguna tontería delante. Las tonterías que sobran se pueden quitar.
En este caso, los elementos con los que nos quedaremos se verán como algo así:
1 |
<svg>
|
2 |
<line/>
|
3 |
<path/>
|
4 |
<line/>
|
5 |
</svg>
|
Dentro de nuestro <svg> principal tenemos un <line>, luego un <path>, luego otro <line>. Se trata de los tres objetos vectoriales que dibujamos antes, diferenciados sólo porque, técnicamente, una línea no tiene curvatura, por lo que en el archivo SVG viene definida de manera diferente a un trazado curvo, a saber "path".
3. Añadir clases
Tendremos que apuntar a estos vectores con CSS por separado un poco más adelante, así que asegúrate de que cada uno tenga un nombre de clase adecuado. Es probable que el elemento <svg> ya tenga un identificador que refleje el nombre que tenía la capa en la aplicación en la que fue diseñado.
1 |
<svg id="signature"> |
2 |
<line class="stroke-I" /> |
3 |
<path class="stroke-an" /> |
4 |
<line class="stroke-flourish" /> |
5 |
</svg>
|
He nombrado mis vectores con nombres de clase relacionados con lo que son (el primero es la "I" de mi nombre, por ejemplo).
4. El resto de atributos SVG
Para ser justos, tu SVG no se verá tan limpio. Cada uno de estos vectores tendrá un montón de coordenadas, además de varios atributos enterrados dentro de ellos. Las coordenadas tendrán que quedarse, pero podemos eliminar algunos de los atributos habituales y colocarlos en cambio en nuestra hoja de estilo CSS, manteniendo las cosas bonitas y limpias.
Nuevo proyecto
Voy a construirlo usando CodePen, pero puedes usar documentos HTML y CSS independientes si lo prefieres. Pega el código SVG directamente en tu documento HTML. A continuación, quita los atributos que tienen en común cada uno de los elementos de trazado y línea , y colócalos en tu archivo de estilos CSS. Por ejemplo, habrás observado atributos como:
-
fill="none" -
stroke="#0F436D" stroke-width="2"stroke-linecap="round"stroke-linejoin="round"stroke-miterlimit="10"
Puedes eliminar estos y añadirlos en su lugar vía CSS, de la siguiente manera:
1 |
path, |
2 |
line { |
3 |
fill: none; |
4 |
stroke: #2a3745; |
5 |
stroke-width: 2; |
6 |
stroke-linecap: round; |
7 |
stroke-linejoin: round; |
8 |
stroke-miterlimit: 10; |
9 |
}
|
¡Mucho más limpio!
5. Comienza a animar
Con el fin de animar los trazos de este SVG vamos a utilizar una técnica planteada por primera vez por Jake Archibald. La idea es la siguiente: a cada uno de estos vectores se le va a dar un trazo discontinuo. Para ello, aplicamos un valor de stroke-dasharray dentro del CSS:
Longitud de cada tramo del trazo discontinuo
Para cada uno de estos vectores hacemos que el stroke-dasharray tenga justamente la misma longitud que el trazado, por lo que cada uno tendrá un solo guión que cubrirá toda su longitud. Para conseguirlo se requiere un poco de prueba y error, en nuestro caso los valores serán los siguientes:
1 |
.stroke-I { |
2 |
stroke-dasharray: 80; |
3 |
}
|
4 |
|
5 |
.stroke-an { |
6 |
stroke-dasharray: 360; |
7 |
}
|
8 |
|
9 |
.stroke-flourish { |
10 |
stroke-dasharray: 40; |
11 |
}
|
Ahora, con el fin de animar estos trazos, necesitamos desplazar cada uno de los guiones para que el espacio vacío cubra el vector, no el guión. ¿Tiene sentido? Estas ilustraciones podrían ayudar. En esta primera, imagina que la línea discontinua se está utilizando para cubrir el remate decorativo al final de la firma.



Ahora en esta hemos compensado el guión, de manera que es el hueco vacío lo que está sobre el origen:



Ahora, todo lo que tenemos que hacer es usar CSS para animar desde el estado desplazado hasta el otro.
6. Fotogramas clave
La animación CSS consiste en definir primero los fotogramas clave. Cada fotograma clave representa estados a lo largo de una línea de tiempo y, después, nuestros navegadores representan las animaciones entre ellos.
Veamos primero cómo se puede animar este desplazamiento de guión. Usaremos el primer trazo, la "I", y animaremos entre dos estados. Empieza configurando algunos fotogramas clave:
1 |
@keyframes write1 { |
2 |
0% { |
3 |
stroke-dashoffset: 80; |
4 |
}
|
5 |
100% { |
6 |
stroke-dashoffset: 0; |
7 |
}
|
8 |
}
|
Aquí le damos un nombre a los fotogramas clave (write1) y usando la sintaxis abreviada especificamos que al principio de la línea de tiempo (0%) queremos que el stroke-dashoffset sea 80. En otras palabras: el guión, que es exactamente 80px de largo, será totalmente desplazado.
Al final de la línea de tiempo (al 100%) queremos que el stroke-dashoffset sea 0, por lo que el guión cubrirá una vez más el vector.
Aplicar la animación
Ahora ya tenemos nuestros fotogramas clave, vamos a vincularlos a una animación. Añadimos otra declaración a nuestra regla stroke-I:
1 |
.stroke-I { |
2 |
stroke-dasharray: 80; |
3 |
animation: write1 3s infinite linear; |
4 |
}
|
Aquí, usando la propiedad animation, indicamos que queremos usar los fotogramas clave write1 definidos hace un momento, queremos que todo dure exactamente 3 segundos, queremos que la animación se reproduzca en bucle infinitamente y que la velocidad sea lineal (para que no haya aceleración o desaceleración).
Esto es lo que obtenemos:
Nota: Estoy usando Autoprefixer en CodePen lo que me ahorra tener que usar prefijos de navegador en el código de la animación.



Aplicar a los tres vectores
Necesitamos definir dos conjuntos más de fotogramas clave (write2 y write3) para los restantes vectores de la firma, y necesitamos crear desplazamientos con las longitudes de guión correctas que descubrimos anteriormente:
1 |
@keyframes write2 { |
2 |
0% { |
3 |
stroke-dashoffset: 360; |
4 |
}
|
5 |
100% { |
6 |
stroke-dashoffset: 0; |
7 |
}
|
8 |
}
|
9 |
|
10 |
@keyframes write3 { |
11 |
0% { |
12 |
stroke-dashoffset: 40; |
13 |
}
|
14 |
100% { |
15 |
stroke-dashoffset: 0; |
16 |
}
|
17 |
}
|
A continuación, tenemos que aplicar esas animaciones a los dos vectores restantes:
1 |
.stroke-an { |
2 |
stroke-dasharray: 360; |
3 |
animation: write2 3s infinite linear; |
4 |
}
|
5 |
|
6 |
.stroke-flourish { |
7 |
stroke-dasharray: 40; |
8 |
animation: write3 3s infinite linear; |
9 |
}
|
Esto es lo que obtenemos:
¡Ahora estamos llegando a algún lado! Cada vector se está animando perfectamente, en un movimiento lineal que dura 3 segundos.
¿El siguiente paso? Para animarlos en secuencia.
7. Animación secuencial
Actualmente tenemos tres trazos que se animan de forma simultánea. Sin embargo, idealmente queremos que la "I" se anime primero, y que luego le siga la "an", y por último la floritura final. Si tuviéramos que visualizar esto a lo largo de una línea de tiempo podría verse así:



En realidad podemos representar estas secciones de la línea de tiempo perfectamente en nuestros fotogramas clave CSS. Por ejemplo, la primera sección (del 0% al 33,3%) es cuando queremos que nuestra "I" se anime, por lo que modificamos los fotogramas clave para que terminen al 33,3% en lugar de al 100%:
1 |
@keyframes write1 { |
2 |
0% { |
3 |
stroke-dashoffset: 80; |
4 |
}
|
5 |
33.3% { |
6 |
stroke-dashoffset: 0; |
7 |
}
|
8 |
}
|
Ahora, dado que las tres animaciones tienen la misma longitud (3 segundos) podemos asegurarnos de que la segunda no se inicie hasta el 33,3%, cuando se complete la primera animación:
1 |
@keyframes write2 { |
2 |
0%, 33.3% { |
3 |
stroke-dashoffset: 360; |
4 |
}
|
5 |
100% { |
6 |
stroke-dashoffset: 0; |
7 |
}
|
8 |
}
|
Esto es lo que nos da:
Completar la secuencia
Las dos primeras animaciones fluyen muy bien, así que vamos a mejorar el conjunto haciendo que la segunda termine al 66,6%, momento en el que la animación final puede iniciarse. Nuestros fotogramas clave tendrán este aspecto:
1 |
@keyframes write1 { |
2 |
0% { |
3 |
stroke-dashoffset: 80; |
4 |
}
|
5 |
33.3% { |
6 |
stroke-dashoffset: 0; |
7 |
}
|
8 |
}
|
9 |
|
10 |
@keyframes write2 { |
11 |
0%, 33.3% { |
12 |
stroke-dashoffset: 360; |
13 |
}
|
14 |
66.6% { |
15 |
stroke-dashoffset: 0; |
16 |
}
|
17 |
}
|
18 |
|
19 |
@keyframes write3 { |
20 |
0%, 66.6% { |
21 |
stroke-dashoffset: 40; |
22 |
}
|
23 |
100% { |
24 |
stroke-dashoffset: 0; |
25 |
}
|
26 |
}
|
Y la secuencia se verá así:
Refinado adicional
Lo que tenemos está bien, pero no es perfecto, ciertamente todavía está lejos de aparentar un movimiento realista escrito con pluma. Cada uno de estos tres vectores se está dibujando en el transcurso de un segundo, con independencia de cuál sea su longitud. El vector medio es mucho más largo que el anterior, por lo que lógicamente debería tardar más tiempo en dibujarse. Una línea de tiempo mejorada podría tener un aspecto similar al siguiente:



Para darle mayor realismo hay incluso un espacio entre el final del primer trazado vectorial y el comienzo del segundo. Así que vamos a alterar los valores de nuestros fotogramas clave para reflejar que:
1 |
@keyframes write1 { |
2 |
0% { |
3 |
stroke-dashoffset: 80; |
4 |
}
|
5 |
20% { |
6 |
stroke-dashoffset: 0; |
7 |
}
|
8 |
}
|
9 |
|
10 |
@keyframes write2 { |
11 |
0%, 25% { |
12 |
stroke-dashoffset: 360; |
13 |
}
|
14 |
90% { |
15 |
stroke-dashoffset: 0; |
16 |
}
|
17 |
}
|
18 |
|
19 |
@keyframes write3 { |
20 |
0%, 90% { |
21 |
stroke-dashoffset: 40; |
22 |
}
|
23 |
100% { |
24 |
stroke-dashoffset: 0; |
25 |
}
|
26 |
}
|
Por último, aceleramos las cosas cambiando todos los valores de 3s a 2s. También podemos actualizar las declaraciones de la animación para que cada una se ejecute una sola vez, no de forma infinita en bucle:
1 |
animation: write1 2s 1 linear; |
También es posible que desees jugar con el valor lineal, en lugar añadir algún efecto tipo ease-in, ease-in-out, ease-out, etc. para hacer el movimiento menos uniforme. ¿Qué nos da todo eso?
Próxima vez
¡Hemos hecho un gran progreso y también hemos aprendido mucho a lo largo del camino! En el siguiente tutorial vamos a dar un paso más, utilizando Waypoints.js para ayudarnos a controlar cuándo tiene lugar la animación. ¡Nos vemos allí!



