Anima en el compositor con transform y opacity, estructura tus @keyframes y respeta las preferencias de movimiento de los usuarios.
Abrir esta lección en KodokonAntes de elegir qué animar, recuerda el pipeline de renderizado: layout (geometría), paint (píxeles), composite (ensamblaje de capas en la GPU). Animar width o top provoca un layout en cada fotograma, a menudo seguido de un paint: esa es la receta del tirón por debajo de los 60 fps. transform y opacity se gestionan directamente en el compositor, sin volver a pasar por las dos primeras etapas. La regla profesional: anima solo esas dos propiedades siempre que sea posible, y simula el resto (translate en vez de top, scale en vez de width).
.button {
transform: translateY(0);
transition:
transform 0.2s cubic-bezier(0.2, 0.8, 0.2, 1),
opacity 0.15s ease-out;
}
.button:hover {
transform: translateY(-2px);
}
.button:active {
transform: translateY(0) scale(0.97);
}Cuando una transición ya no basta (pasos intermedios, bucles, inicio automático), pasa a @keyframes. Dos ajustes marcan la diferencia entre una animación limpia y un fallo visual: animation-fill-mode controla el estado antes del inicio (backwards aplica el primer fotograma clave durante el retardo) y después del final (forwards congela el último); both combina ambos. Ten en cuenta también que la función de temporización se aplica entre cada par de fotogramas clave, no sobre la duración total: puedes redefinirla dentro de un fotograma clave.
@keyframes slide-in {
from {
transform: translateX(-100%);
opacity: 0;
}
70% {
transform: translateX(8px);
opacity: 1;
}
to {
transform: translateX(0);
}
}
.toast {
animation: slide-in 0.35s ease-out both;
}Dos herramientas complementarias que conviene conocer. will-change: transform promueve el elemento a su propia capa antes de la animación, evitando un rasterizado tardío; pero cada capa cuesta memoria de GPU, así que aplícalo justo antes de la animación y quítalo después, nunca como un estilo permanente en decenas de elementos. steps(n) reemplaza la interpolación continua por saltos discretos: esencial para sprites, cursores tipo máquina de escribir o relojes.
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}transform: translateX(100px) en lugar de left: 100px para un desplazamiento animado?transform tiene mejor soporte en navegadores antiguostransform lo gestiona el compositor sin recalcular el layout en cada fotogramaleft solo funciona en elementos posicionados de forma absoluta, transform funciona en todas partestransform acepta valores negativos, a diferencia de leftanimation-fill-mode: both?will-change?* para acelerar toda la páginatransform: translateZ(0)transition para microinteracciones