Las funciones de aceleración de CSS tradicionales, como ease-in o cubic-bezier(), se limitan a curvas simples, lo que hace imposible crear efectos complejos basados en la física, como rebotes o resortes. La función de tiempo linear() resuelve este problema, ya que te permite proporcionar una serie de paradas que pueden aproximarse a curvas complejas. Las transiciones y las animaciones se interpolan en función de líneas rectas entre las paradas, pero con suficientes paradas, puede parecer fluido.
Pasos de implementación
- Genera los puntos de detención de la curva:
Trazar manualmente decenas de puntos para un resorte o un rebote no es práctico. Usa una función de sincronización de una biblioteca externa o una herramienta para convertir una función de aceleración de JavaScript existente o una ruta de acceso SVG en la sintaxis de
linear(). Opcional: Almacena estas funciones de tiempo como propiedades personalizadas de CSS para reutilizarlas en todo tu sitio. - Define la función de tiempo:
Aplica las paradas generadas a la propiedad
transition-timing-functionoanimation-timing-function, o a través de las abreviaturastransitionoanimation. - Ajusta la duración:
A diferencia de los motores de física de JavaScript, en los que la duración se deriva de las propiedades físicas (masa, rigidez), CSS aún requiere un
durationfijo. Es posible que debas ajustar la duración para obtener el efecto deseado.
Ejemplo: Desaceleración de resorte
En este ejemplo, se muestra cómo usar una función linear() personalizada para crear un efecto de resorte que supere el valor objetivo antes de estabilizarse.
.spring {
/* Define the physics-based easing as a reusable variable */
--spring-easing: linear(0, 0.016 0.5%, 0.06 1%, 0.226 2%, 1.116 5.4%, 1.375 6.6%, 1.527 7.7%, 1.565 8.2%, 1.585 8.8%, 1.581 9.3%, 1.559 9.8%, 1.458 10.9%, 0.937 14.3%, 0.784 15.5%, 0.693 16.6%, 0.67 17.1%, 0.657 17.7%, 0.671 18.7%, 0.729 19.8%, 1.042 23.3%, 1.13 24.5%, 1.182 25.6%, 1.201 26.7%, 1.192 27.7%, 1.156 28.8%, 0.977 32.2%, 0.925 33.4%, 0.894 34.5%, 0.882 35.6%, 0.887 36.6%, 0.907 37.7%, 1.045 42.4%, 1.069 44.5%, 1.059 46.3%, 0.979 50.9%, 0.96 53.4%, 0.966 55.3%, 1.013 59.9%, 1.024 62.3%, 0.986 71.2%, 1.008 79.9%, 0.995 88.9%, 1);
/* Apply the easing with a duration that fits the spring's complexity */
/* MANDATORY: Always include a duration; linear() does not calculate it automatically */
transition: scale 0.8s var(--spring-easing);
}
.spring:hover {
scale: 1.2;
}
Ejemplo: Ejemplo: Aceleración de rebote
En este ejemplo, se muestra cómo usar una función linear() personalizada para crear un efecto de rebote.
.bounce {
/* Define the physics-based easing as a reusable variable */
--bounce-easing: linear(0, 0.214 14.7%, 0.386 23.7%, 0.598 31.9%, 0.999 44.7%, 0.807 52.6%, 0.762 56%, 0.747 59.4%, 0.758 62.4%, 0.793 65.6%, 0.999 77.4%, 0.961 81.2%, 0.949 84.8%, 0.956 88%, 0.993 95.5%, 1);
/* Apply the easing with a duration that fits the bounce's complexity */
/* MANDATORY: Always include a duration; linear() does not calculate it automatically */
transition: scale 0.4s var(--bounce-easing);
}
.bounce:hover {
scale: 1.2;
}
Consideraciones clave
- Rendimiento: Para obtener las animaciones basadas en la física más fluidas, aplica
linear()a las propiedades que se ejecutan en un subproceso independiente, comotransformyopacity. - Precisión vs. carga útil: Si bien más paradas generan una curva más suave, también aumentan el tamaño de tu CSS. La mayoría de los generadores te permiten "simplificar" la curva para encontrar el equilibrio óptimo entre la suavidad y el tamaño del código.
- Evita la opacidad para los rebotes: Aplicar aceleraciones de rebote a
opacitypuede causar un parpadeo visualmente discordante si el valor supera el rango de 0 a 1. - Accesibilidad: Las animaciones complejas basadas en la física pueden distraer o causar sensibilidad al movimiento en algunos usuarios. Respeta siempre las preferencias del usuario reduciendo o inhabilitando estas animaciones.
@media (prefers-reduced-motion: reduce) {
.element {
transition: none;
}
}
Estrategias de resguardo
Resguardo de CSS
Para los navegadores que no admiten linear(), proporciona una función de aceleración estándar como resguardo. El navegador ignorará el valor linear() si no lo reconoce y recurrirá a la declaración válida anterior.
.element {
/* Fallback for older browsers (standard smooth exit) */
transition: transform 0.8s ease-out;
/* Modern browsers will override with the physics-based easing */
transition-timing-function: linear(0, 1.1, 0.95, 1.02, 1);
}
Resguardo de la biblioteca de JavaScript (Motion/GSAP)
Opcional: Si una animación física de alta fidelidad es fundamental incluso en navegadores más antiguos, usa una biblioteca de JavaScript como Motion (motion.dev) o GSAP (greensock.com) para controlar la animación cuando no se admita linear().
- Detecta la compatibilidad: Usa
CSS.supports()para verificar si el navegador controla la funciónlinear(). - Carga o aplica de forma condicional: Si no se admite, usa la implementación de resorte o rebote de la biblioteca.
/* Detect if the browser supports the linear() function */
const supportsLinearEasing = window.CSS && CSS.supports('animation-timing-function', 'linear(0, 1)');
if (!supportsLinearEasing) {
/*
Example using Motion (motion.dev) for a spring fallback.
This should only be initialized if native CSS support is missing.
*/
import("https://cdn.jsdelivr.net/npm/motion@latest/dist/motion.js").then(({ animate, spring }) => {
animate(".element", { transform: "scale(1.2)" }, {
easing: spring({ stiffness: 100, damping: 10 })
});
});
}
También puedes usar @supports en CSS para una detección de funciones más explícita:
@supports not (animation-timing-function: linear(0, 1)) {
.element {
/* Alternative experience for unsupported browsers */
transition-duration: 0.4s;
transition-timing-function: cubic-bezier(0.34, 1.56, 0.64, 1);
}
}