Animando spritesheets CSS

Usando steps() con imágenes de sprites


La función steps() que explicamos en el artículo anterior permite dividir una animación en intervalos escalonados de tiempo idénticos. Esto permite, de forma muy sencilla, crear animaciones basadas en spritesheets CSS.

¿Qué es un Sprite Sheet CSS?

Los spritesheets CSS, como su propio nombre indica, son hojas de sprites basadas en CSS, o lo que es lo mismo: imágenes con varias viñetas o fotogramas de un elemento o personaje, para crear una animación artística a partir de ella.

Por ejemplo, lo que vemos a continuación es un sprite sheet CSS de Bernard Bernoulli, uno de los personajes del videojuego The Day of the Tentacle:

Bernard Bernoulli, de The Day of the Tentacle

El spritesheet en cuestión debe cumplir una serie de requisitos para que se pueda utilizar para crear una animación CSS:

  • 1️⃣ Cada viñeta debe ocupar exactamente lo mismo (mismo ancho y alto).
  • 2️⃣ Las viñetas deben estar ordenadas en una línea horizontal (o vertical).

Si la imagen cumple dichos requisitos, obtengamos la siguiente información, ya que la necesitaremos para crear la animación:

  • 1️⃣ Cantidad de fotogramas (número de viñetas): 6
  • 2️⃣ Ancho y alto del spritesheet (total de la imagen): 672x156
  • 3️⃣ Ancho y alto de cada viñeta (fotograma): 112x156

Observa que el ancho de cada viñeta (112) multiplicado por el número de viñetas (6) es el mismo que el tamaño total de ancho de la imagen: 112 x 6 = 672. Coincide.

Animar el spritesheet con linear

Teniendo en cuenta estos datos, podemos intentar crear una animación, creando un rectángulo con la imagen de fondo del spritesheet y moviendo la posición de la imagen en el rectángulo.

Si además, animamos la posición de la imagen con background-position en el eje X podemos obtener una animación simple que, aunque no es lo que buscamos, se puede entender como funciona este primer paso:

.bernard {
  width: 112px;
  height: 156px;
  border: 4px solid blue;
  background-image: url("bernard-bernoulli.png");
  animation: walk 5s linear infinite;
}

@keyframes walk {
  to { background-position: -672px; }
}
<div class="bernard"></div>

Estamos moviendo la posición de la imagen hacia la izquierda, ya que hemos puesto el background-position en valor negativo.

Animar el spritesheet con steps()

Las funciones de salto steps() que vimos en el artículo anterior son especialmente interesantes para hacer animaciones con spritesheets de imágenes. Como nuestra imagen tiene 6 viñetas o fotogramas, utilizaremos steps(6) en lugar de linear, aumentaremos un poco la velocidad bajando los 5s a 0.75s y retiraremos el borde azul:

.bernard {
  width: 112px;
  height: 156px;
  background-image: url("bernard-bernoulli.png");
  animation: walk 0.75s steps(6) infinite;
}

@keyframes walk {
  to { background-position: -672px; }
}
<div class="bernard"></div>

Ahora la animación walk salta de fotograma en fotograma, produciendo el efecto de animación deseado. Sin embargo, el personaje se encuentra estático en el mismo lugar, vamos a moverlo de sitio.

Mover el personaje horizontalmente

Vamos a añadir una nueva animación move, que se producirá a la vez que la animación walk que ya teníamos. Esta nueva animación move moverá al personaje utilizando la propiedad translate para moverlo horizontalmente.

Le aplicaremos una duración de 6s y se desplazará 600px a la derecha. A mitad de la animación, volverá a su punto de partida:

.bernard {
  width: 112px;
  height: 156px;
  background-image: url("bernard-bernoulli.png");
  animation:
    walk 0.75s steps(6) infinite,
    move 6s linear normal infinite;
}

@keyframes walk {
  to { background-position: -672px; }
}

@keyframes move {
  0% { translate: 0 }
  50% { translate: 600px }
  100% { translate: 0 }
}
<div class="bernard"></div>

Sin embargo, a menos que se trate de Michael Jackson, la animación hacia atrás tiene un pequeño problema. El personaje se mueve hacia atrás, sin darse la vuelta. Vamos a solucionarlo.

Girar el personaje en la vuelta

Utilizando una nueva animación, vamos a darle la vuelta al personaje utilizando la propiedad CSS scale. Esta propiedad nos permite cambiar la escala horizontal y vertical. Utilizando un valor de 1, se queda exactamente igual, pero utilizando un valor -1, la invierte.

Vamos a aprovechar esto, para añadir una nueva animación mirror de 6s de duración. Observa que hemos utilizado la función de tiempo steps(1), para crear dos «escalones»: uno la ida del personaje a la derecha, y el segundo la vuelta del personaje, invirtiéndolo con scale:

.bernard {
  width: 112px;
  height: 156px;
  background-image: url("bernard-bernoulli.png");
  animation:
    walk 0.75s steps(6) infinite,
    move 6s linear normal infinite,
    mirror 6s steps(1) normal infinite;
}

@keyframes walk {
  to { background-position: -672px; }
}

@keyframes move {
  0% { translate: 0 }
  50% { translate: 600px }
  100% { translate: 0 }
}

@keyframes mirror {
  0% { scale: 1 1; }
  50% { scale: -1 1; }
}
<div class="bernard"></div>

Observa que scale: -1 1 hace que invierta el personaje en el eje X (horizontal) pero no en el eje Y, para que no aparezca boca abajo.

Tienes otro ejemplo similar en Codepen, en esta ocasión con Guybrush Threepwood de la primera parte de la saga del videojuego Monkey Island.

¿Quién soy yo?

Soy Manz, vivo en Tenerife (España) y soy streamer partner en Twitch y profesor. Me apasiona el universo de la programación web, el diseño y desarrollo web y la tecnología en general. Aunque soy full-stack, mi pasión es el front-end, la terminal y crear cosas divertidas y locas.

Puedes encontrar más sobre mi en Manz.dev