Funciones de tiempo

Cambiando el ritmo con propiedades *-timing-function


Tanto cuando hablamos de transiciones como cuando hablamos de animaciones tenemos dos propiedades que se aplican exactamente igual y se encargan de definir el ritmo o transcurso de la animación o transición en cuestión.

Las funciones de tiempo en CSS

Dichas propiedades son las siguientes:

Propiedades Descripción Valor
transition-timing-function Ritmo de la transición | cubic-bezier(A, B, C, D)
animation-timing-function Ritmo de la animación | cubic-bezier(A, B, C, D)

Cualquiera de estas dos propiedades permite indicar el ritmo de la transición/animación en cuestión.

Valores predefinidos

Quizás, la forma más sencilla de indicar el ritmo de una animación, sería especificar una de las siguientes palabras clave (valores) que existen para indicar en las propiedades anteriores. Cada una de ella, realiza la animación a un ritmo diferente:

Valor Inicio Transcurso Final Equivalente en cubic-beizer
ease Lento Rápido Lento cubic-bezier(0.25, 0.1, 0.25, 1)
linear Normal Normal Normal cubic-bezier(0, 0, 1, 1)
ease-in Lento Normal Normal cubic-bezier(0.42, 0, 1, 1)
ease-out Normal Normal Lento cubic-bezier(0, 0, 0.58, 1)
ease-in-out Lento Normal Lento cubic-bezier(0.42, 0, 0.58, 1)
cubic-bezier(A, B, C, D) - - - Transición personalizada

Si no se indica ninguna función de tiempo concreta, CSS utilizará la función de tiempo ease. Sin embargo, podemos utilizar cualquiera de las anteriores.

La función de tiempo linear quizás sea la más sencilla de entender, ya que siempre va al mismo ritmo, un ritmo constante. Por su parte, ease comienza suavemente, continua de forma más rápida y termina suavemente de nuevo. Las funciones de tiempo ease-in y ease-out son variaciones que van más lento al principio o al final, y la función de tiempo ease-in-out es una mezcla de las dos anteriores.

.element {
  width: 200px;
  height: 50px;
  margin: 5px;
  background: indigo;
  color: white;
  animation: animated 2s alternate infinite;
}

@keyframes animated {
  to { width: 500px; }
}

.ease { animation-timing-function: ease; }
.linear { animation-timing-function: linear; }
.ease-in { animation-timing-function: ease-in; }
.ease-out { animation-timing-function: ease-in-out; }
.ease-in-out { animation-timing-function: ease-in-out; }
<div class="element ease">ease</div>
<div class="element linear">linear</div>
<div class="element ease-in">ease-in</div>
<div class="element ease-out">ease-out</div>
<div class="element ease-in-out">ease-in-out</div>

En el caso de que ninguna de ellas nos ofrezca el ritmo que buscamos, quizás nuestra mejor opción sea definirla manualmente mediante cubic-bezier().

Función cubic-bezier()

La función de tiempo cubic-bezier() es una función personalizada, donde podemos darle unos valores concretos depediendo de la velocidad que queramos que tenga la transición. En la última columna de la tabla anterior podemos ver los valores equivalentes a cada una de las palabras clave mencionadas como linear, ease, ease-in, ease-out o ease-in-out.

En principio, el formato de la función es cubic-bezier(A, B, C, D), donde esos cuatro parámetros son números que indican lo siguiente:

Parámetro Valor Descripción Pertenece a
A X1 Eje X del primer punto que orienta la curva bezier. P1
B Y1 Eje Y del primer punto que orienta la curva bezier. P1
C X2 Eje X del segundo punto que orienta la curva bezier. P2
D Y2 Eje Y del segundo punto que orienta la curva bezier. P2

Cubic Bezier

.element {
  width: 200px;
  height: 50px;
  margin: 5px;
  background: deeppink;
  color: white;
  animation: animated 1s infinite alternate;
}

@keyframes animated {
  to { width: 500px; }
}

.cubic-bezier { animation-timing-function: cubic-bezier(1, 0.50, 0.90, 0.25); }
.linear { animation-timing-function: linear; }
<div class="element cubic-bezier">cubic-bezier</div>
<div class="element linear">linear</div>

Todo esto se puede ver muy fácilmente usando la herramienta Cubic Bezier, donde puedes crear de forma interactiva el ritmo de las transiciones o animaciones, con los parámetros deseados.

Función linear()

Recientemente, se ha añadido una nueva función CSS que permite crear ritmos altamente personalizados, donde incluso la función cubic-bezier() se nos podría quedar corta. Se trata de la función linear(), la cuál admite una lista de valores numéricos entre 0 y 1 (con decimales), que permitirán específicar exactamente la transición:

.container {
  background: grey;
  width: 200px;
  height: 400px;
}

.element {
  height: 200px;
  background: indigo;
  animation: move 5s infinite;
  animation-timing-function: linear(
    0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1,
    0.5, 0.6, 0.7, 0.8, 0.9, 1,
    0.7, 0.8, 0.9, 1,
    0.8, 0.9, 1,
    0.9, 1,
    1);
}

@keyframes move {
  from { transform: translateY(0); }
  to { transform: translateY(200px); }
}
<div class="container">
  <div class="element"></div>
</div>

Observa que tenemos una caja de 200x200 píxels. Dicha caja se va a mover desde su posición original a una posición 200px más abajo. Mediante la propiedad animation-timing-function vamos a modificar su ritmo. Ten en cuenta que lo he separado en varias líneas para que sea más fácil de explicar:

  • Fragmento 1: valores de 0 a 1. Desplazamiento desde inicio (0) a fin (200px).
  • Fragmento 2: valores de 0.5 a 1. Desplazamiento desde mitad (100px) a fin (200px).
  • Fragmento 3: valores de 0.7 a 1. Desplazamiento desde 70% (170px) a fin (200px).
  • Fragmento 4: valores de 0.8 a 1. Desplazamiento desde 80% (180px) a fin (200px).
  • Fragmento 5: valores de 0.9 a 1. Desplazamiento desde 90% (190px) a fin (200px).

Esto hará que produzca una especie de efecto rebote (muy artificial, habría que añadir más valores para hacerla más natural). Entre un fragmento y otro habrá un movimiento rápido, ya que no hemos hecho el fragmento a la inversa (de 1 a 0.5, por ejemplo).

La compatibilidad de esta función linear() actualmente es la siguiente:

Función de salto

Por último, a parte de las funciones de suavizado predefinidas y las cubic bezier, también es posible utilizar funciones de salto, que pueden ser muy útiles en ciertas ocasiones.

Las funciones de salto permiten establecer una transición o animación en un número concreto de pasos muy específico, que se pasa por parámetro n. En este ejemplo, estamos indicando que la animación debe tener exactamente 5 pasos, por lo que en lugar de ser una transición o animación fluida, será una escalonada en el número de pasos dados:

.container {
  width: 600px;
  background: grey;
}

.element {
  width: 200px;
  height: 200px;
  background: indigo;
  animation: move 5s infinite;
  animation-timing-function: steps(5);
}

@keyframes move {
  to { transform: translateX(500px); }
}
<div class="container">
  <div class="element"></div>
</div>

Hay ciertas variaciones de las funciones escalonadas de salto, son las siguientes:

Valor Descripción Equivalente
steps(n, jump-start) Divide el transcurso en n saltos y omite el primer paso.
steps(n, jump-end) Divide el transcurso en n saltos y omite el último paso.
steps(n, jump-none) Divide el transcurso en n saltos y no omite ningún paso.
steps(n, jump-both) Divide el transcurso en n saltos y omite el primer y último paso.
steps(n) Alias de jump-end Equivale a steps(n, jump-end)
steps(n, start) Alias de jump-start Equivale a steps(n, jump-start)
steps(n, end) Alias de jump-end Equivale a steps(n, jump-end)
step-start Función de salto predefinida Equivale a steps(1, jump-start)
step-end Función de salto predefinida Equivale a steps(1, jump-end)

Estas funciones de salto pueden ser especialmente interesantes para hacer animaciones con spritesheets de imágenes, como por ejemplo, este de Guybrush Threepwood de Monkey Island. En ella, realizamos una animación que no nos interesa que sea animada, sino que se pueda saltar entre viñetas para replicar el efecto de una animación:

Monkey Island - Guybrush Threepwood CSS animation

Tienes un artículo donde explico como funciona en Animar personajes con CSS utilizando a Bernard Bernoulli, uno de los personajes del juego El día del Tentáculo:

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

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

¿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