Animaciones (animation)

Profesores:JAB y Ester Torres

Animation

De una manera parecida a las transiciones, pero con una mayor potencialidad, en HTML5 tenemos a nuestra disposición las animaciones (animation).

Para empezar con algo sencillo, primero vamos a hacer paso a paso que el martillo (creado en SVG) -y que ya hemos utilizado en otros temas- gire al colocar el cursor encima.

Sitúa el cursor encima del martillo para ver la animación.


Paso a paso

1. Creamos el objeto a animar
Primero, creamos dentro de un <div> el objeto, imagen o texto que realizará la animación (en este caso, el martillo).

Así, dentro de la página html, creamos un <div> llamado martillo y dentro creamos un dibujo SVG del martillo que rotará.

<div id="martillo">
  <svg width="120" height="190" xmlns="http://www.w3.org/2000/svg")>
    <rect x="43" y="10" width="14" height="160" rx="6" ry="5" fill="#895111"/>
    <rect x="43" y="10" width="14" height="160" rx="6" ry="5" fill="#895111"/>
    <rect x="45" y="15" width="4" height="150" rx="6" ry="6" fill="#A68661"/>
    <rect x="10" y="22" width="80" height="45" rx="14" ry="12" fill="#6E6E5F"/>
    <rect x="20" y="37" width="62" height="24" rx="6" ry="6" fill="#898982"/>
    <rect x="20" y="25" width="62" height="6" rx="4" ry="4" fill="#C2C2B6"/>
    <rect x="43" y="67" width="14" height="9" fill="#482907"/>
  </svg>
</div>
2. Establecemos la animación
Seguidamente, en el código CSS, vamos a incluir dos cosas.
Por una parte, en el selector del <div> donde está el martillo, indicamos qué animación tendrá que reproducir, indicando un nombre y la duración de la animación expresada en segundos (entre otras propiedades opcionales que a continuación veremos).
#martillo {
  animation:animacion_martillo 2s;
}
El nombre de la animación (animación_martillo) y la duración (2s) son valores obligatorios, pero existen valores opcionales que nos permiten personalizar la animación, como son:

Así, el ejemplo anterior podría estar complementado por estas propiedades:
(Se podría escribir todo seguido, pero debido al número de valores y al orden existente para definirlos, posiblemente es más sencillo ir indicando las propiedades opcionales por separado):
#martillo {
  animation:animacion_martillo 2s;
  animation-timing-function: ease-out;
  animation-iteration-count: infinite;
  animation-direction: alternate;
  animation-delay: 1s; 
}
3. Definimos cómo será la animación
Igualmente, dentro del mismo código CSS, definimos en qué consistirá dicha animación, indicando el nombre 'animacion_martillo', que hemos creado en el paso anterior.
@keyframes animacion_martillo {
  0% {
    transform: rotate(0deg);
  }
  50% {
    transform: rotate(90deg);
  }
  100% {
    transform: rotate(0deg);
  }
}
Toda la animación se puede dividir en tantos pasos como sea necesario, aunque lo mínimo son 2: inicio (0%) y final (100%).

En este ejemplo se han incluido 3 pasos. En el inicio de la animación (0%) se empieza con una rotación del <div> martillo de 0 grados (0deg), en la mitad de la animación (50%), el <div> martillo tendrá una rotación de 90 grados (rotará hacia la derecha) y cuando la animación finalice (100%), el martillo volverá a su rotación inicial.

Ejemplo práctico complejo

El siguiente ejemplo es bastante más complejo, ya que se relacionan 2 animaciones, además de mejorar un poco la animación del martillo para que gire de una manera algo más natural y clave el clavo.

Al mismo tiempo, se ha utilizado el parámetro opcional infinite para que la animación se realice de manera cíclica.

/* cabeza */

Primero, vamos a mejorar un poco el movimiento del martillo.
Como habrás podido observar (al comparar este movimiento con el ejemplo del principio de este tema) el movimiento de este martillo, aparte de rotar se desplaza hacia abajo para poder llegar hasta el clavo (no se limita a rotar desde su eje central).

Además, al impactar contra el clavo permanece un poco más de tiempo rotado (no sube tan rápidamente).

Para solucionar el primer aspecto hemos añadido el código rojo:
@keyframes animacion_martillo {
  0% {
    transform: rotate(0deg);
    top:0px
  }
  50% {
    transform: rotate(90deg);
    top:57px
  }
  100% {
    transform: rotate(0deg);
    top:0px
  }
}
Siempre que utilizemos las propiedades -top-, -left- o -right- debemos indicar si la posición que estamos indicando es absoluta (toma como referencia las coordenadas de la página html) o relativa (toma como referencia la posición donde está colocado el objeto, en este caso el <div> del martillo), por lo que tenemos que añadir también otra línea de código en el otro apartado del CSS:
#martillo {
  animation:animacion_martillo 2s;
  position:relative;
}
En el caso del primer código, hemos añadido la propiedad top (que define la posición vertical de un elemento) para que cuando la animación llegue a su 50% de reproducción (a parte de girar 90 grados) también baje 57 píxeles. Al haber indicado position:relative le estamos definiendo que tiene que bajar 57 píxeles respecto a la posición relativa del <div> martillo, no de la página.

Pero con esto arreglamos el problema de que el martillo rotase de una manera más natural, pero no el hecho de que al impactar contra el clavo, éste se quede un rato más prolongado en la posición girada.

Para solucionar este problema vamos a realizar dos acciones. Primero, vamos a añadir un paso más a los tres que ya teníamos (quedando en cuatro pasos y modificando un poco los porcentajes centrales):
@keyframes animacion_martillo {
  0% {
    transform: rotate(0deg);
    top:0px
  }
  42% {
    transform: rotate(90deg);
    top:57px
  }
  60% {
    transform: rotate(90deg);
    top:57px
  }
  100% {
    transform: rotate(0deg);
    top:0px
  }
}
Ahora, el martillo acaba de girar cuando la animación llega al 42% de su recorrido (no en el 50% como antes) y hasta el 60% no vuelve a subir (antes empezaba a subir inmediatamente después de llegar al 50%). Por lo que en este caso, el martillo queda rotado 90 grados un 18% de la animación

Así,al tratarse de una animación de 2 segundos:

Compatibilidades con todos los navegadores

Como ocurre con otras funcionalidades de HTML5 todavía es necesario añadir los prefijos para que todos los navegadores (excepto Opera -que aunque funciona, no funciona bien del todo- e Internet Explorer -que, como siempre, no funciona ni bien ni mal, simplemente "no funciona") entiendan estos códigos.

Aunque en este caso este proceso de repetición de código es todavía más asfixiante, ya que no se limita a una sola línea por navegador, sino que se tiene que repetir todo el bloque de código, quedando de la siguiente extensa manera:
@keyframes animacion_martillo {
  0% {
    transform: rotate(0deg);
    top:0px
  }
  42% {
    transform: rotate(90deg);
    top:57px
  }
  60% {
    transform: rotate(90deg);
    top:57px
  }
  100% {
    transform: rotate(0deg);
    top:0px
  }
}

@-webkit-keyframes animacion_martillo {
  0% {
    -webkit-transform: rotate(0deg);
    top:0px
  }
  42% {
    -webkit-transform: rotate(90deg);
    top:57px
  }
  60% {
    -webkit-transform: rotate(90deg);
    top:57px
  }
  100% {
    -webkit-transform: rotate(0deg);
    top:0px
  }
}

@-moz-keyframes animacion_martillo {
  0% {
    -moz-transform: rotate(0deg);
    top:0px
  }
  42% {
    -moz-transform: rotate(90deg);
    mtop:57px
  }
  60% {
    -moz-transform: rotate(90deg);
    top:57px
  }
  100% {
    -moz-transform: rotate(0deg);
    top:0px
  }
}

@-o-keyframes animacion_martillo {
  0% {
    -o-transform: rotate(0deg);
    top:0px
  }
  42% {
    -o-transform: rotate(90deg);
    top:57px
  }
  60% {
    -o-transform: rotate(90deg);
    top:57px
  }
  100% {
    -o-transform: rotate(0deg);
    top:0px
  }
}
En este extenso código todavía no se ha añadido el prefijo -ms- para cuando Internet Explorar acepte animation.

Y por último quedaría la especificación de la animación, que después de la repetición continua del ejemplo anterior no representaría ningún exceso desmesurado:
#martillo {
  animation:animacion_martillo 2s;
  -webkit-animation:animacion_martillo 2s;
  -moz-animation:animacion_martillo 2s;
  -o-animation:animacion_martillo 2s;
}