Cómo funciona @keyframes en CSS explicado fácil

Las animaciones en CSS pueden parecer un detalle pequeño dentro de una interfaz, pero cuando están bien planteadas ayudan a que una web se sienta más fluida, clara y cuidada. Un botón que aparece suavemente, una tarjeta que entra en pantalla, un loader que gira mientras carga el contenido o un icono que llama la atención sin resultar molesto tienen algo en común: muchas veces están creados con @keyframes en CSS.

La regla @keyframes permite definir una animación paso a paso. Es decir, le indica al navegador cómo debe cambiar un elemento desde un estado inicial hasta un estado final, pasando por todos los puntos intermedios que queramos controlar.

Si ya has trabajado con transiciones o estás empezando a explorar el movimiento en interfaces, este concepto es clave para entender mejor las animaciones CSS y aplicarlas con criterio en tus proyectos.

En este artículo vamos a ver cómo funciona @keyframes en CSS, cuál es su sintaxis, qué propiedades intervienen, cuándo conviene usarlo y qué buenas prácticas deberías tener en cuenta para crear animaciones útiles, accesibles y fáciles de mantener.

Qué es @keyframes en CSS

@keyframes es una regla de CSS que se utiliza para definir los distintos estados de una animación. Su función principal es describir cómo cambia un elemento a lo largo del tiempo.

Dicho de forma sencilla, @keyframes CSS marca los pasos de una animación.

Por ejemplo, podemos hacer que un elemento pase de estar invisible a visible, que se desplace de izquierda a derecha, que cambie de tamaño, que rote, que parpadee o que combine varias transformaciones a la vez.

La estructura básica es esta:

@keyframes nombreAnimacion {
  from {
    opacity: 0;
  }

  to {
    opacity: 1;
  }
}

En este caso, la animación empieza con una opacidad de 0, por lo que el elemento no se ve. Después termina con una opacidad de 1, de modo que aparece completamente visible.

Pero definir el @keyframes no es suficiente. Para que la animación se aplique a un elemento, necesitamos usar la propiedad animation.

.caja {
  animation: nombreAnimacion 1s ease-in-out;
}

Aquí estamos indicando que el elemento con clase .caja debe usar la animación llamada nombreAnimacion, que tendrá una duración de 1s y una curva de movimiento ease-in-out.

Cómo funciona @keyframes paso a paso

Para entender bien las animaciones con keyframes, conviene separar el proceso en dos partes: primero se define la animación y después se aplica al elemento.

1. Definir la animación con @keyframes

La regla @keyframes funciona como una especie de guion. Dentro de ella escribimos qué cambios queremos que ocurran durante la animación.

Podemos usar from y to cuando solo necesitamos indicar un punto inicial y un punto final.

@keyframes aparecer {
  from {
    opacity: 0;
  }

  to {
    opacity: 1;
  }
}

Este ejemplo es muy común para crear un efecto de aparición suave.

También podemos escribirlo con porcentajes:

@keyframes aparecer {
  0% {
    opacity: 0;
  }

  100% {
    opacity: 1;
  }
}

Ambas versiones hacen lo mismo. from equivale a 0% y to equivale a 100%.

La ventaja de usar porcentajes es que podemos añadir pasos intermedios. Por ejemplo, podemos hacer que un elemento no solo aparezca, sino que también se mueva, crezca o rebote durante el proceso.

2. Aplicar la animación con animation

Una vez definida la animación, necesitamos aplicarla a un selector CSS.

.elemento {
  animation-name: aparecer;
  animation-duration: 1s;
  animation-timing-function: ease;
}

También podemos escribirlo de forma abreviada:

.elemento {
  animation: aparecer 1s ease;
}

La propiedad animation es un shorthand, es decir, una forma resumida de escribir varias propiedades relacionadas con la animación.

Esta separación es importante: @keyframes define qué ocurre, mientras que animation define cómo se ejecuta.

Propiedades principales de CSS animation keyframes

Para trabajar correctamente con CSS animation keyframes, no basta con conocer @keyframes. También es importante entender las propiedades que controlan cómo se reproduce la animación.

animation-name

La propiedad animation-name indica el nombre de la animación que queremos aplicar.

.elemento {
  animation-name: aparecer;
}

Ese nombre debe coincidir con el nombre definido en @keyframes.

@keyframes aparecer {
  from {
    opacity: 0;
  }

  to {
    opacity: 1;
  }
}

Si el nombre no coincide, la animación no funcionará. Este es uno de los errores más habituales cuando se empieza a trabajar con keyframes CSS.

animation-duration

animation-duration define cuánto dura la animación.

.elemento {
  animation-duration: 2s;
}

Puede expresarse en segundos (s) o milisegundos (ms).

.elemento {
  animation-duration: 500ms;
}

Una duración demasiado corta puede pasar desapercibida. Una duración demasiado larga puede resultar pesada. En interfaces web, muchas microinteracciones suelen funcionar bien entre 150ms y 500ms, aunque depende del tipo de efecto y del contexto.

Por ejemplo, no es lo mismo animar el hover de un botón que una entrada de contenido más elaborada. En el primer caso, una duración breve suele ser suficiente. En el segundo, puede tener sentido usar un tiempo algo mayor.

animation-timing-function

La propiedad animation-timing-function controla la velocidad de la animación a lo largo del tiempo.

.elemento {
  animation-timing-function: ease-in-out;
}

Algunos valores frecuentes son:

  • linear: mantiene una velocidad constante.
  • ease: empieza suave, acelera y termina suave.
  • ease-in: empieza lento y acelera.
  • ease-out: empieza rápido y termina lento.
  • ease-in-out: empieza y termina suavemente.

También se puede usar cubic-bezier() para crear una curva personalizada.

.elemento {
  animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
}

Este nivel de control es útil cuando queremos que el movimiento tenga una sensación más natural.

animation-delay

animation-delay permite retrasar el inicio de la animación.

.elemento {
  animation-delay: 1s;
}

Esto significa que la animación empezará un segundo después de que se aplique.

Es especialmente útil cuando queremos animar varios elementos de forma escalonada, por ejemplo, una lista de tarjetas que aparece una detrás de otra.

.card:nth-child(1) {
  animation-delay: 0ms;
}

.card:nth-child(2) {
  animation-delay: 120ms;
}

.card:nth-child(3) {
  animation-delay: 240ms;
}

Este recurso puede ayudar a crear una sensación de continuidad, siempre que no se abuse de él.

animation-iteration-count

animation-iteration-count define cuántas veces se repite la animación.

.elemento {
  animation-iteration-count: 3;
}

Si queremos que se repita indefinidamente, usamos infinite.

.loader {
  animation: girar 1s linear infinite;
}

Este valor se utiliza mucho en loaders, iconos animados o efectos decorativos en bucle.

Aun así, conviene usarlo con moderación. Una animación infinita puede ser útil cuando informa de que algo está cargando, pero puede resultar molesta si se utiliza solo como recurso decorativo.

animation-direction

animation-direction indica la dirección en la que se reproduce la animación.

.elemento {
  animation-direction: alternate;
}

Algunos valores posibles son:

  • normal: la animación va de principio a fin.
  • reverse: la animación se reproduce al revés.
  • alternate: alterna entre ida y vuelta.
  • alternate-reverse: alterna, pero empieza al revés.

Esto resulta muy útil para animaciones que deben ir y volver, como un elemento flotando suavemente.

animation-fill-mode

animation-fill-mode controla qué estilos conserva el elemento antes o después de la animación.

.elemento {
  animation-fill-mode: forwards;
}

El valor forwards hace que el elemento conserve el estado final de la animación.

Por ejemplo, si una tarjeta entra desde abajo y termina en su posición normal, forwards permite que se quede en esa posición al terminar.

@keyframes subir {
  from {
    transform: translateY(40px);
    opacity: 0;
  }

  to {
    transform: translateY(0);
    opacity: 1;
  }
}

.tarjeta {
  animation: subir 600ms ease-out forwards;
}

Sin forwards, el elemento podría volver a su estado inicial al finalizar la animación, algo que muchas veces no queremos.

Ejemplo práctico de @keyframes CSS

Veamos un ejemplo completo. Imagina que queremos animar una tarjeta para que aparezca suavemente desde abajo.

<div class="card">
  <h2>Animación con CSS</h2>
  <p>Esta tarjeta aparece con un movimiento suave.</p>
</div>
.card {
  max-width: 320px;
  padding: 24px;
  border-radius: 16px;
  background: #ffffff;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.12);

  animation: entradaTarjeta 600ms ease-out forwards;
}

@keyframes entradaTarjeta {
  0% {
    opacity: 0;
    transform: translateY(32px);
  }

  100% {
    opacity: 1;
    transform: translateY(0);
  }
}

En este caso, la tarjeta empieza con opacity: 0, por lo que no se ve. Además, tiene transform: translateY(32px), así que aparece ligeramente desplazada hacia abajo.

Al llegar al 100%, la tarjeta ya es visible y vuelve a su posición natural.

Este tipo de animación es muy útil para mejorar la percepción de fluidez en una interfaz. No es una animación decorativa sin sentido: ayuda a que el contenido aparezca de una forma más amable y menos brusca.

Si estás creando interfaces con componentes reutilizables, este mismo enfoque puede combinarse con metodologías de diseño más ordenadas, como explico en el artículo sobre metodologías de desarrollo de software, especialmente cuando trabajas en proyectos donde diseño, desarrollo y experiencia de usuario deben avanzar de forma coordinada.

Usar porcentajes intermedios en @keyframes

Una de las ventajas de @keyframes CSS es que no estamos limitados a un inicio y un final. Podemos añadir tantos puntos intermedios como necesitemos.

@keyframes rebote {
  0% {
    transform: translateY(0);
  }

  30% {
    transform: translateY(-30px);
  }

  60% {
    transform: translateY(10px);
  }

  100% {
    transform: translateY(0);
  }
}

Este ejemplo crea una animación de rebote. El elemento sube, baja un poco y vuelve a su posición original.

.boton {
  animation: rebote 700ms ease-in-out;
}

Los porcentajes intermedios permiten construir animaciones más expresivas. Sin embargo, conviene usarlos con criterio. Cuantos más pasos añadimos, más compleja se vuelve la animación y más fácil es que el resultado parezca exagerado.

Cuándo usar varios pasos

Usar varios porcentajes tiene sentido cuando queremos crear una secuencia clara. Por ejemplo:

  • Un icono que rebota.
  • Un loader con varios estados.
  • Una ilustración que cambia de posición.
  • Un elemento que entra, se agranda y vuelve a su tamaño normal.
  • Un aviso que llama la atención con un pequeño movimiento.

Cuándo evitar demasiados pasos

No siempre hace falta complicar una animación. Si solo queremos suavizar un cambio entre dos estados, puede bastar con una transición o con un @keyframes muy sencillo.

La clave está en hacerse una pregunta antes de añadir movimiento: ¿esta animación ayuda a entender mejor la interfaz o solo añade ruido visual?

Diferencia entre transition y @keyframes

Una duda muy común cuando se empieza a trabajar con animaciones en CSS es cuándo usar transition y cuándo usar @keyframes.

La diferencia principal es esta:

transition suaviza el cambio entre dos estados.
@keyframes permite crear una secuencia de animación con uno o varios pasos.

Por ejemplo, si queremos que un botón cambie de color al pasar el ratón por encima, lo más lógico es usar transition.

.boton {
  background: #753a88;
  transition: background 200ms ease;
}

.boton:hover {
  background: #cc2b5e;
}

Aquí solo hay dos estados: normal y hover. Por eso transition es suficiente.

En cambio, si queremos que un icono pulse constantemente, necesitamos una animación con @keyframes.

.icono {
  animation: pulso 1.5s ease-in-out infinite;
}

@keyframes pulso {
  0% {
    transform: scale(1);
  }

  50% {
    transform: scale(1.12);
  }

  100% {
    transform: scale(1);
  }
}

Aquí no estamos simplemente pasando de un estado a otro por una interacción del usuario. Estamos creando una secuencia que se repite en el tiempo.

Regla rápida para elegir

Una forma sencilla de decidir es esta:

Si hay dos estados, usa transition.
Si hay una secuencia, repetición o control avanzado, usa @keyframes.

Esta regla no cubre todos los casos posibles, pero ayuda mucho cuando estás empezando.

También es útil relacionarlo con el diseño de experiencia de usuario. El movimiento no debería añadirse solo porque “queda bonito”, sino porque ayuda a comunicar mejor una acción o un cambio de estado. Esta idea conecta directamente con temas como el Efecto Patito de Goma aplicado al desarrollo: muchas veces, explicar qué queremos que haga una interfaz nos ayuda a elegir mejor la solución técnica.

Animaciones útiles con keyframes CSS

Las animaciones con keyframes pueden aplicarse a muchos elementos de una web. Lo importante es que tengan una intención clara.

Animación de aparición suave

@keyframes fadeIn {
  from {
    opacity: 0;
  }

  to {
    opacity: 1;
  }
}

.elemento {
  animation: fadeIn 400ms ease forwards;
}

Es una de las animaciones más sencillas y más utilizadas. Sirve para mostrar contenido sin que aparezca de golpe.

Animación de entrada lateral

@keyframes slideIn {
  from {
    opacity: 0;
    transform: translateX(-40px);
  }

  to {
    opacity: 1;
    transform: translateX(0);
  }
}

.menu {
  animation: slideIn 500ms ease-out forwards;
}

Puede funcionar bien en menús, paneles, banners o bloques de contenido.

Loader giratorio

.loader {
  width: 40px;
  height: 40px;
  border: 4px solid #eeeeee;
  border-top-color: #cc2b5e;
  border-radius: 50%;
  animation: girar 800ms linear infinite;
}

@keyframes girar {
  to {
    transform: rotate(360deg);
  }
}

Este ejemplo es muy habitual para indicar que una acción está en proceso. La animación es infinita porque el loader debe seguir girando mientras se carga el contenido.

Efecto flotante

@keyframes flotar {
  0% {
    transform: translateY(0);
  }

  50% {
    transform: translateY(-12px);
  }

  100% {
    transform: translateY(0);
  }
}

.ilustracion {
  animation: flotar 3s ease-in-out infinite;
}

Este tipo de animación suele usarse en ilustraciones, iconos decorativos o elementos destacados. Debe ser suave para no cansar al usuario.

Buenas prácticas para usar @keyframes en CSS

Las animaciones pueden mejorar mucho una interfaz, pero también pueden empeorarla si se usan sin criterio. Por eso es importante aplicar algunas buenas prácticas.

Usa transform y opacity siempre que puedas

Cuando animes elementos, intenta priorizar propiedades como transform y opacity.

.elemento {
  transform: translateY(20px);
  opacity: 0;
}

Estas propiedades suelen ser más eficientes para el navegador que animar valores como width, height, top, left o margin.

Por ejemplo, en lugar de mover un elemento con top, es preferible usar transform: translate().

@keyframes moverConTop {
  from {
    top: 0;
  }

  to {
    top: 100px;
  }
}

@keyframes moverConTransform {
  from {
    transform: translateY(0);
  }

  to {
    transform: translateY(100px);
  }
}

Esto ayuda a que la animación sea más fluida y tenga mejor rendimiento.

No abuses de las animaciones infinitas

Las animaciones infinitas pueden ser útiles, pero también pueden distraer. Un loader giratorio tiene sentido porque informa al usuario de que algo está cargando. Un icono que no deja de moverse sin motivo puede resultar molesto.

Antes de usar infinite, pregúntate si la animación realmente necesita repetirse todo el tiempo.

.elemento {
  animation-iteration-count: infinite;
}

Si no aporta información o contexto, quizá es mejor evitarlo.

Cuida la accesibilidad

No todas las personas perciben el movimiento de la misma manera. Algunas animaciones pueden causar incomodidad, mareo o dificultad para concentrarse.

Por eso es buena práctica respetar la preferencia del usuario con prefers-reduced-motion.

@media (prefers-reduced-motion: reduce) {
  * {
    animation-duration: 0.01ms;
    animation-iteration-count: 1;
    scroll-behavior: auto;
  }
}

También puedes desactivar animaciones concretas:

@media (prefers-reduced-motion: reduce) {
  .ilustracion {
    animation: none;
  }
}

Esto demuestra cuidado por la experiencia de todas las personas usuarias.

La accesibilidad no debería tratarse como un extra, sino como parte del propio proceso de diseño y desarrollo. Igual que cuidamos la estructura, los textos o la jerarquía visual, también deberíamos cuidar cómo se comporta el movimiento en pantalla.

Mantén nombres claros

El nombre de una animación debe explicar qué hace.

@keyframes fadeIn {
}

@keyframes slideUp {
}

@keyframes pulse {
}

Evita nombres poco descriptivos como animacion1, movimiento2 o efectoFinal.

En proyectos grandes, una nomenclatura clara ayuda mucho a mantener el CSS ordenado.

Evita animar demasiados elementos a la vez

Una página con muchas animaciones simultáneas puede parecer desordenada y afectar al rendimiento. Además, si todo se mueve, nada destaca.

La animación debe guiar la atención, no competir por ella.

Una buena práctica es reservar las animaciones para momentos concretos:

  • Entrada de contenido importante.
  • Confirmación de una acción.
  • Estados de carga.
  • Feedback visual.
  • Microinteracciones relevantes.

Errores comunes al trabajar con @keyframes CSS

Aunque @keyframes es bastante fácil de entender, hay errores frecuentes que pueden hacer que la animación no funcione como esperamos.

El nombre de la animación no coincide

.caja {
  animation: aparecerCaja 1s ease;
}

@keyframes aparecer {
  from {
    opacity: 0;
  }

  to {
    opacity: 1;
  }
}

En este caso, la animación no se aplicará porque el elemento llama a aparecerCaja, pero el @keyframes se llama aparecer.

La solución es usar exactamente el mismo nombre.

.caja {
  animation: aparecer 1s ease;
}

Falta la duración

.caja {
  animation-name: aparecer;
}

Si no indicamos una duración, la animación no tendrá tiempo para ejecutarse como esperamos. Por eso siempre conviene añadir animation-duration o usar el shorthand completo.

.caja {
  animation: aparecer 1s ease;
}

El elemento vuelve a su estado inicial

Esto ocurre cuando la animación termina y no se conserva el estado final.

.caja {
  animation: subir 500ms ease;
}

Si queremos que el elemento conserve el último estado de la animación, podemos añadir forwards.

.caja {
  animation: subir 500ms ease forwards;
}

Usar animaciones donde bastaría una transición

No todo necesita @keyframes. Si solo quieres suavizar un hover, un cambio de color o una apertura sencilla, probablemente transition sea suficiente.

Usar la herramienta adecuada hace que el CSS sea más limpio y fácil de mantener.

Este mismo criterio también se puede aplicar a otros aspectos del desarrollo frontend. Por ejemplo, cuando eliges entre una solución sencilla o una más compleja en React, conviene pensar primero en el problema que quieres resolver. Si estás en esa fase de aprendizaje, puede ayudarte esta guía sobre cómo aprender React desde cero.

Ejemplo completo: botón con efecto de pulso

Veamos ahora un ejemplo completo de un botón que llama la atención con un pulso suave.

<button class="cta-button">
  Ver proyecto
</button>
.cta-button {
  padding: 14px 24px;
  border: 0;
  border-radius: 999px;
  background: #cc2b5e;
  color: #ffffff;
  font-size: 1rem;
  font-weight: 600;
  cursor: pointer;

  animation: pulsoSuave 2s ease-in-out infinite;
}

@keyframes pulsoSuave {
  0% {
    transform: scale(1);
    box-shadow: 0 0 0 0 rgba(204, 43, 94, 0.35);
  }

  70% {
    transform: scale(1.04);
    box-shadow: 0 0 0 14px rgba(204, 43, 94, 0);
  }

  100% {
    transform: scale(1);
    box-shadow: 0 0 0 0 rgba(204, 43, 94, 0);
  }
}

Este efecto puede ayudar a destacar una llamada a la acción, pero debe usarse con moderación. Si todos los botones de una web tienen animaciones infinitas, el efecto deja de ser útil y puede resultar invasivo.

Una alternativa más equilibrada sería activar la animación solo en momentos concretos o aplicarla a un único CTA principal.

@keyframes y diseño de interfaces: no todo es decoración

Uno de los errores más habituales al hablar de animaciones CSS es pensar que solo sirven para “hacer bonito”. En realidad, el movimiento puede tener una función muy importante dentro de una interfaz.

Una buena animación puede:

  • Ayudar a entender que un elemento ha aparecido o desaparecido.
  • Indicar que una acción está en progreso.
  • Guiar la atención hacia una zona concreta.
  • Reforzar una interacción.
  • Hacer que los cambios de estado sean más naturales.

Por ejemplo, cuando se abre un menú lateral, una animación de entrada puede ayudar a entender de dónde viene ese panel. Cuando aparece un mensaje de confirmación, una pequeña transición puede hacer que el cambio sea más claro. Cuando se carga contenido, un loader evita que el usuario piense que la página se ha quedado bloqueada.

La clave está en usar las animaciones con keyframes como parte de la comunicación visual, no como un adorno añadido al final.

Esto también tiene relación con el diseño UI/UX. Una herramienta como Figma puede ayudarte a pensar y prototipar estos comportamientos antes de llevarlos a código. Si te interesa esa parte del proceso, puedes ampliar con el artículo sobre pros y contras de usar Figma como herramienta de diseño UI/UX.

Cómo organizar keyframes en un proyecto CSS

En proyectos pequeños, puedes escribir los @keyframes cerca del componente o bloque donde se utilizan. Pero en proyectos más grandes, conviene mantener cierto orden.

Agrupar animaciones reutilizables

Si tienes animaciones que se repiten en varias partes del sitio, puedes crear una sección específica para ellas.

@keyframes fadeIn {
  from {
    opacity: 0;
  }

  to {
    opacity: 1;
  }
}

@keyframes slideUp {
  from {
    opacity: 0;
    transform: translateY(24px);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

Después puedes aplicarlas en distintos componentes.

.card {
  animation: slideUp 500ms ease-out forwards;
}

.modal {
  animation: fadeIn 300ms ease forwards;
}

Crear clases utilitarias

Otra opción es crear clases reutilizables.

.animate-fade-in {
  animation: fadeIn 400ms ease forwards;
}

.animate-slide-up {
  animation: slideUp 500ms ease-out forwards;
}

Esto puede ser útil si trabajas con una metodología de estilos más modular o si quieres aplicar animaciones de forma consistente.

Documentar las animaciones importantes

Si una animación tiene una función concreta dentro del diseño, merece la pena documentarla. No hace falta escribir una novela, pero sí dejar claro para qué sirve.

@keyframes cardEntrance {
  from {
    opacity: 0;
    transform: translateY(32px);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

Este tipo de organización ayuda a que otras personas del equipo entiendan por qué existe esa animación.

@keyframes en CSS y rendimiento web

El rendimiento es otro aspecto importante cuando hablamos de animaciones. Una animación puede verse muy bien en un ordenador potente, pero funcionar peor en dispositivos más antiguos o en móviles con menos recursos.

Por eso, al trabajar con @keyframes, conviene tener en cuenta tres ideas básicas.

Prioriza animaciones ligeras

Las propiedades transform y opacity suelen ser las mejores candidatas para animar porque permiten movimientos fluidos sin forzar tantos recálculos visuales.

En cambio, animar propiedades relacionadas con el layout, como width, height, top, left, margin o padding, puede generar más trabajo para el navegador.

No animes todo al cargar la página

Animar demasiados elementos al mismo tiempo puede ralentizar la experiencia inicial. Si todo entra, rebota, gira y aparece a la vez, la página pierde claridad.

Es mejor seleccionar algunos elementos clave y usar el movimiento para reforzar la jerarquía visual.

Comprueba la experiencia en móvil

Muchas veces diseñamos y probamos animaciones en escritorio, pero gran parte del tráfico llega desde móvil. Una animación que parece sutil en una pantalla grande puede resultar excesiva en una pantalla pequeña.

Por eso conviene probar siempre cómo se siente la animación en diferentes tamaños de pantalla.

Preguntas frecuentes sobre @keyframes en CSS

¿Qué diferencia hay entre @keyframes y animation en CSS?

@keyframes define los pasos de la animación, mientras que animation aplica esa animación a un elemento y controla aspectos como la duración, la repetición, el retraso o la curva de movimiento.

Dicho de otra forma: @keyframes describe qué ocurre y animation indica cómo y cuándo se ejecuta.

¿Puedo usar @keyframes para animar cualquier propiedad CSS?

Técnicamente, muchas propiedades CSS pueden animarse, pero no todas son igual de recomendables. Para obtener mejores resultados, suele ser preferible animar transform y opacity, porque ofrecen mejor rendimiento y suelen generar movimientos más fluidos.

Animar propiedades como width, height, top, left o margin puede ser más costoso para el navegador, sobre todo si se aplica a muchos elementos a la vez.

¿Cuándo debería usar @keyframes en lugar de transition?

Conviene usar @keyframes cuando necesitas una secuencia, una repetición o varios pasos intermedios. Por ejemplo, un loader giratorio, un efecto de pulso, una entrada elaborada o una animación que se repite.

En cambio, si solo quieres suavizar el cambio entre dos estados, como un hover o un menú que se abre y se cierra, probablemente sea mejor usar transition.

Cuando el movimiento también comunica

Aprender cómo funciona @keyframes en CSS es mucho más que memorizar una sintaxis. Es entender que el movimiento forma parte del diseño de una interfaz.

Una animación bien planteada no está ahí para llamar la atención porque sí. Está ahí para acompañar al usuario, explicar un cambio, suavizar una transición o reforzar una acción. Por eso, antes de añadir un efecto, conviene preguntarse qué aporta.

@keyframes CSS te da mucho control: puedes definir estados, crear secuencias, repetir movimientos y construir efectos visuales complejos sin necesidad de JavaScript. Pero ese control también requiere criterio.

Si estás empezando, quédate con esta idea: usa keyframes CSS cuando necesites controlar una animación paso a paso. Para cambios simples entre dos estados, una transition suele ser suficiente. Para secuencias, repeticiones y movimientos más elaborados, @keyframes es la herramienta adecuada.

Al final, animar bien no significa mover más cosas. Significa moverlas mejor. Y cuando el movimiento tiene intención, la interfaz se siente más clara, más fluida y mucho más cuidada.

Cómo hacer emails responsive sin volverte loca con tablas HTML

Crear emails responsive puede parecer una especie de castigo técnico si vienes del desarrollo web moderno. Estás acostumbrada a trabajar con flexbox, grid, componentes reutilizables, estilos organizados y layouts que responden con bastante elegancia. Pero, de repente, entras en el mundo del email marketing y todo cambia: aparecen las tablas HTML para email, los estilos inline, las limitaciones de Outlook y ese miedo constante a que algo se vea bien en Gmail pero se rompa en otro cliente de correo.

Y sí, es normal preguntarse: ¿de verdad seguimos usando tablas HTML para maquetar emails en pleno 2026? La respuesta es que sí, aunque con matices. Las tablas no se usan porque sean la opción más moderna ni la más cómoda, sino porque siguen siendo una de las formas más fiables de conseguir compatibilidad entre distintos clientes de correo.

La buena noticia es que no necesitas volverte loca escribiendo veinte niveles de tablas anidadas sin criterio. Hoy puedes crear emails responsive con tablas HTML de forma más ordenada, predecible y mantenible si entiendes qué papel cumple cada capa, qué CSS puedes usar con seguridad y cuándo conviene apoyarte en herramientas como MJML.

Si estás empezando en este tema, puede venirte bien complementar este artículo con la guía sobre qué es MJML y por qué facilita la maquetación de emails responsive, porque te ayudará a entender cómo simplificar parte del trabajo sin perder de vista lo que ocurre por debajo.

Por qué los emails responsive siguen usando tablas HTML

Cuando hablamos de tablas HTML en email, no hablamos de una recomendación estética. Hablamos de una solución práctica ante un entorno bastante irregular. El problema principal es que los clientes de correo no se comportan como los navegadores modernos. Gmail, Outlook, Apple Mail, Yahoo Mail y otros clientes interpretan el HTML y el CSS con diferencias importantes.

En una página web puedes crear un layout responsive con display: grid, display: flex, gap, clamp() o incluso container queries. En email, en cambio, muchas de esas decisiones pueden fallar o no comportarse igual en todos los entornos. Por eso las tablas siguen teniendo tanto peso: permiten crear una estructura base relativamente estable.

No son cómodas, no son bonitas y no son semánticamente ideales para maquetar diseño visual, pero ayudan a que el email mantenga su forma en clientes que todavía no interpretan CSS moderno de manera consistente.

La diferencia entre maquetar una web y maquetar un email

El error más común al empezar con emails responsive es intentar aplicar la misma mentalidad que usarías en una web. Pero un email no es una landing page. No tienes el mismo control sobre el entorno, no puedes asumir que todo el CSS será respetado y tampoco puedes depender de archivos externos como harías en un proyecto frontend tradicional.

En email, la pregunta no es solo: “¿este diseño queda bonito?”. La pregunta real es: “¿este diseño se mantiene suficientemente bien en la mayor cantidad posible de clientes de correo?”

Ese cambio de enfoque modifica por completo la forma de trabajar. En lugar de perseguir una maquetación perfecta al píxel, conviene pensar en sistemas robustos: una estructura sencilla, una anchura máxima razonable, columnas que puedan apilarse, botones legibles y una versión móvil que no obligue al usuario a hacer zoom.

No se trata de amar las tablas, sino de usarlas con estrategia

Las tablas HTML en email son una herramienta. Nada más. No hace falta defenderlas como si fueran modernas ni odiarlas como si fueran el enemigo absoluto. Lo importante es entender cuándo cumplen una función útil.

Una tabla puede servir como contenedor principal del email. Otra puede organizar una sección de dos columnas. Otra puede asegurar que un botón se vea correctamente en distintos clientes. El problema aparece cuando se usan tablas sin estructura, sin nombres de clases claros y sin una lógica de componentes.

Ahí es cuando el email se convierte en una maraña difícil de mantener. Pero si trabajas con una arquitectura clara, incluso una plantilla basada en tablas puede ser relativamente limpia.

La estructura base de un email responsive con tablas HTML

Antes de entrar en trucos responsive, necesitas una base sólida. Un buen email HTML suele tener tres niveles principales: el fondo general, el contenedor central y los bloques de contenido.

La idea más habitual es trabajar con un contenedor de unos 600 px de ancho máximo, porque históricamente ha sido una medida segura para muchas newsletters, campañas comerciales y emails informativos. Aunque hoy se pueden crear diseños más amplios, ese ancho sigue siendo una referencia práctica.

Ejemplo básico de estructura con tablas HTML

<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0">
  <tr>
    <td align="center">
      <table role="presentation" width="600" cellspacing="0" cellpadding="0" border="0">
        <tr>
          <td>
            Contenido del email
          </td>
        </tr>
      </table>
    </td>
  </tr>
</table>

Este ejemplo no pretende ser una plantilla final, sino mostrar la idea: una tabla exterior ocupa el ancho completo y centra una tabla interior de anchura controlada.

El contenedor exterior

El contenedor exterior suele ocupar el 100% del ancho. Sirve para definir el fondo general del email y para centrar el contenido. Esta capa es importante porque muchos clientes de correo necesitan estructuras explícitas para respetar alineaciones y fondos.

Aquí puedes aplicar un color de fondo general, por ejemplo un gris claro, y luego colocar dentro el contenido principal sobre fondo blanco. Es una estructura sencilla, pero efectiva.

El contenedor interior

El contenedor interior es el cuerpo real del email. Normalmente se define con un ancho fijo, como 600, y se complementa con estilos que permitan cierta flexibilidad en móvil.

En emails responsive es habitual combinar atributos HTML antiguos, como width="600", con CSS inline y reglas en el bloque <style>. Puede parecer redundante, pero en email la redundancia muchas veces es una forma de defensa.

Las secciones internas

Dentro del contenedor principal puedes crear secciones: cabecera, bloque hero, texto, columnas, llamada a la acción, pie de email, etc.

La clave está en no meter todo en una única tabla gigante sin separación lógica. Aunque el HTML final use tablas, tú puedes pensar en componentes: header, hero, bloque de texto, bloque de dos columnas, botón y footer.

Esa forma de pensar te ayudará a mantener el código más limpio y a reutilizar patrones. Si además estás comparando formas de trabajar, te puede interesar el artículo sobre MJML vs HTML tradicional para emails: ventajas y limitaciones, donde se ve mejor cuándo compensa escribir HTML manual y cuándo conviene automatizar parte del proceso.

Cómo hacer que las tablas HTML funcionen en móvil

El gran reto no es crear un email con tablas. El reto es conseguir que ese email sea responsive. Para eso necesitas combinar varias técnicas: anchuras fluidas, imágenes adaptables, columnas que se apilan y media queries cuando el cliente de correo las soporte.

Lo importante es no depender de una sola técnica. Una buena plantilla de email debe seguir siendo legible incluso aunque una media query no se aplique correctamente.

Usa una estructura fluida siempre que puedas

Una estrategia bastante segura es no depender exclusivamente de una media query. Puedes definir tablas con width="100%" en determinados bloques y limitar el ancho máximo del contenedor principal.

Las imágenes deberían incluir una combinación de atributo HTML y CSS inline similar a esta:

<img src="imagen.jpg" width="600" style="display:block; width:100%; max-width:600px; height:auto;" alt="Descripción de la imagen">

Esto permite que la imagen se reduzca en pantallas pequeñas sin deformarse. El atributo width ayuda a algunos clientes de correo, mientras que el CSS aporta flexibilidad.

Apila columnas en pantallas pequeñas

Uno de los patrones más habituales en emails responsive es el bloque de dos columnas. En escritorio puedes mostrar imagen y texto lado a lado. En móvil, lo más cómodo es apilar ambos elementos.

Con tablas HTML, esto suele hacerse creando dos celdas o dos tablas internas que, mediante clases y media queries, pasan a ocupar el 100% del ancho en móvil.

@media only screen and (max-width: 600px) {
  .column {
    display: block !important;
    width: 100% !important;
    max-width: 100% !important;
  }
}

Este tipo de regla permite que una estructura pensada para escritorio se adapte mejor a pantallas pequeñas. Aun así, conviene diseñar siempre con una base sencilla. Si el email solo funciona cuando todo el CSS se aplica perfectamente, probablemente sea demasiado frágil.

No dependas de una única solución responsive

Una buena plantilla de email responsive no debería romperse si una media query falla. Este es uno de los cambios de mentalidad más importantes respecto al desarrollo web tradicional.

En web solemos confiar bastante en CSS. En email, conviene diseñar para la imperfección. Eso significa que el diseño base debe ser legible incluso antes de aplicar mejoras responsive.

Si tu versión sin media queries ya es aceptable, las media queries se convierten en una mejora progresiva, no en una condición de supervivencia.

CSS en emails responsive: lo justo, lo compatible y lo necesario

El CSS en email merece un capítulo aparte. Aquí no se trata de escribir menos CSS porque sí, sino de escribir el CSS que realmente aporta valor y tiene posibilidades razonables de funcionar.

Muchas propiedades modernas pueden ser útiles en determinados clientes, pero no todas son fiables para construir la estructura principal de un email. Por eso conviene trabajar con un criterio muy claro: usar CSS moderno solo cuando haya fallback o cuando el fallo no comprometa la lectura del contenido.

Para profundizar en este punto, puedes leer también qué partes de CSS funcionan realmente en email marketing, donde se explica qué propiedades conviene usar con más prudencia.

Estilos inline: incómodos, pero necesarios

Los estilos inline siguen siendo habituales porque muchos clientes de correo los respetan mejor que los estilos externos. Esto hace que el código sea más verboso, pero también más resistente.

<td style="font-family: Arial, sans-serif; font-size:16px; line-height:24px; color:#222222;">
  Texto del email
</td>

¿Es elegante? No demasiado. ¿Es práctico? Sí.

Una forma de no volverte loca es no escribir todo a mano en producción. Puedes trabajar con herramientas que automaticen el CSS inline o con frameworks que generen el HTML final.

Media queries: útiles, pero con fallback

Las media queries son muy útiles para ajustar tamaños de fuente, apilar columnas, modificar paddings o centrar elementos en móvil. Pero no conviene usarlas como única garantía.

Un uso razonable sería:

@media only screen and (max-width: 600px) {
  .mobile-padding {
    padding-left: 20px !important;
    padding-right: 20px !important;
  }

  .mobile-center {
    text-align: center !important;
  }

  .fluid {
    width: 100% !important;
    max-width: 100% !important;
  }
}

El uso de !important es bastante común en email porque las reglas inline pueden tener más peso que las reglas declaradas en el bloque <style>. No es una práctica que trasladaríamos alegremente a una web moderna, pero en email responde a una necesidad real.

Evita CSS demasiado moderno si no tienes alternativa

Puedes usar CSS moderno en algunos contextos, pero siempre con cuidado. Flexbox, grid, variables CSS, filtros, posicionamiento complejo o animaciones pueden funcionar en algunos clientes y fallar en otros.

Si decides usarlos, que sea como mejora progresiva, no como base estructural. Para layouts principales, las tablas siguen siendo más fiables. Para detalles visuales secundarios, puedes experimentar un poco más.

Accesibilidad en emails con tablas HTML

Uno de los puntos más importantes, y a veces olvidados, es la accesibilidad. Si usas tablas para maquetar, debes evitar que los lectores de pantalla interpreten esas tablas como datos tabulares.

Para eso se utiliza role="presentation" en las tablas que cumplen una función puramente visual.

Cuándo usar role=»presentation»

Si una tabla solo sirve para colocar una imagen junto a un texto, centrar un botón o estructurar el layout del email, puedes usar:

<table role="presentation" cellspacing="0" cellpadding="0" border="0">

Esto ayuda a que la experiencia sea más limpia para personas que usan tecnologías de asistencia.

Cuándo no usarlo

Si la tabla contiene datos reales, como precios, horarios, comparativas o resultados, entonces no deberías usar role="presentation". En ese caso, la tabla sí tiene significado semántico y debe conservarlo.

La diferencia es sencilla: si la tabla organiza diseño, es presentación. Si la tabla organiza datos, es contenido.

No olvides el texto alternativo

Las imágenes en emails suelen tener mucho peso visual, pero no siempre cargan por defecto. Por eso el atributo alt es fundamental.

Un buen texto alternativo debe describir la función de la imagen, no rellenarse con palabras clave sin sentido.

<img src="newsletter-responsive.jpg" alt="Ilustración de una newsletter responsive adaptándose a móvil">

El SEO importa, pero la accesibilidad y la claridad también. Una imagen puede reforzar la comprensión del mensaje, pero el contenido esencial debería seguir siendo accesible aunque esa imagen no cargue.

Cómo simplificar el trabajo con MJML

Si tu objetivo es crear emails responsive sin pelearte constantemente con tablas HTML, MJML puede ser una gran ayuda. MJML permite escribir emails con una sintaxis más sencilla y después compilar ese código a HTML compatible con clientes de correo.

La idea es trabajar con etiquetas como <mj-section>, <mj-column>, <mj-text> o <mj-image>, en lugar de escribir manualmente toda la estructura de tablas.

Qué problema resuelve MJML

MJML no elimina las tablas del resultado final. Lo que hace es evitar que tengas que escribirlas tú manualmente en cada plantilla.

Por ejemplo, en lugar de construir una sección de dos columnas con varias tablas anidadas, puedes escribir algo más parecido a esto:

<mj-section>
  <mj-column>
    <mj-image src="imagen.jpg" alt="Imagen descriptiva" />
  </mj-column>
  <mj-column>
    <mj-text>
      Texto del email
    </mj-text>
  </mj-column>
</mj-section>

Después, MJML genera el HTML final con las tablas, estilos y ajustes necesarios.

Si quieres verlo desde un enfoque más práctico, puedes continuar con la guía sobre cómo crear tu primera newsletter responsive con MJML, donde el proceso se entiende mejor paso a paso.

Cuándo te conviene usar MJML

MJML es especialmente útil si vas a crear varias newsletters, plantillas transaccionales o campañas con estructuras repetidas. También es una buena opción si quieres mantener una lógica de componentes y evitar que cada email se convierta en un archivo imposible de leer.

No obstante, sigue siendo importante entender cómo funcionan las tablas HTML en email. Aunque uses MJML, tarde o temprano tendrás que revisar el HTML generado, corregir un comportamiento concreto o adaptar una sección a las limitaciones de un cliente de correo.

Buenas prácticas para no volverte loca con tablas HTML en email

La mejor forma de sobrevivir al desarrollo de emails responsive con tablas HTML es trabajar con método. No improvises cada plantilla desde cero.

Crea una plantilla base reutilizable

Ten una estructura inicial con contenedor exterior, contenedor central, header, bloque de contenido, botón, footer, clases responsive básicas y estilos de texto definidos.

Esto te permitirá empezar cada email desde una base probada, no desde una página en blanco. Además, te ayudará a detectar antes los errores, porque sabrás qué partes de la plantilla ya funcionan correctamente.

Trabaja por bloques, no por pantallas completas

En lugar de pensar “voy a maquetar todo el email”, piensa en bloques independientes: bloque hero, bloque texto más imagen, bloque CTA, bloque testimonios, bloque de producto o bloque footer.

Cada bloque debería poder moverse, duplicarse o eliminarse sin romper toda la plantilla. Esta forma de trabajar se parece más a una lógica de componentes, aunque el resultado final esté construido con tablas.

Prueba antes de enviar

No basta con abrir el HTML en el navegador. Un email puede verse perfecto en Chrome y fallar en Outlook. Siempre que sea posible, prueba en distintos clientes o utiliza herramientas específicas de testing.

Como mínimo, revisa Gmail en escritorio, Gmail en móvil, Apple Mail, Outlook, modo oscuro, imágenes bloqueadas y vista móvil real.

Reduce la ambición visual

Un email no necesita comportarse como una web completa. A veces, cuanto más complejo es el diseño, más posibilidades hay de que algo falle.

En email marketing, la claridad suele ganar a la sofisticación. Un buen email responsive debe ser legible, rápido de escanear, accesible y fácil de accionar. Si además es bonito, mejor. Pero la belleza no debería depender de una estructura frágil.

Errores comunes al crear emails responsive con tablas HTML

Uno de los errores más frecuentes es usar demasiadas columnas. Un diseño de tres o cuatro columnas puede verse bien en escritorio, pero convertirse en un problema en móvil. Si el contenido es importante, asegúrate de que se pueda leer cómodamente en una sola columna.

Otro error habitual es olvidar los paddings móviles. Un email que se ve perfecto en escritorio puede quedar pegado a los bordes en móvil si no defines espaciados adaptados.

También conviene evitar imágenes con texto incrustado. Si el texto importante está dentro de una imagen, puede no ser accesible, no escalar bien o perderse si la imagen no carga.

Y, por último, cuidado con los botones falsos hechos solo con imágenes. Un botón debería ser texto HTML dentro de una estructura clicable, no una imagen que desaparece si el cliente bloquea recursos externos.

Preguntas frecuentes sobre tablas HTML y emails responsive

¿Es obligatorio usar tablas HTML para crear emails responsive?

No es obligatorio en todos los casos, pero sí sigue siendo una de las opciones más compatibles para estructuras principales. Puedes apoyarte en CSS moderno como mejora progresiva, pero para layouts robustos las tablas HTML siguen siendo muy utilizadas en email.

¿Puedo usar flexbox o grid en emails HTML?

Puedes usarlos en algunos contextos, pero no deberías depender de ellos para la estructura principal si necesitas compatibilidad amplia. El soporte de flexbox y grid en clientes de correo no es tan consistente como en navegadores modernos, así que conviene usarlos solo con fallback o en elementos secundarios.

¿MJML evita tener que aprender tablas HTML para email?

MJML reduce muchísimo la necesidad de escribir tablas manualmente, pero no elimina la conveniencia de entenderlas. Es una herramienta muy útil para crear emails responsive de forma más cómoda, aunque el HTML final seguirá usando estructuras compatibles con clientes de correo.

Emails más simples, menos quebraderos de cabeza

Hacer emails responsive con tablas HTML no tiene por qué convertirse en una pesadilla. Es verdad que el desarrollo de emails tiene reglas propias, limitaciones incómodas y decisiones que pueden parecer anticuadas si vienes del desarrollo web moderno. Pero también es cierto que, con una buena estructura base, algunos patrones reutilizables y una mentalidad de compatibilidad, el proceso se vuelve mucho más llevadero.

La clave está en dejar de pelearte con las tablas como si fueran una anomalía y empezar a verlas como una capa de compatibilidad. No necesitas escribir el email más sofisticado del mundo. Necesitas crear una pieza que se lea bien, se adapte al móvil, respete la accesibilidad y funcione en los clientes de correo más importantes.

En email, menos suele ser más. Menos columnas, menos dependencias, menos CSS experimental y menos obsesión por el píxel perfecto. A cambio, más claridad, más consistencia y más tranquilidad.

Porque al final, un buen email responsive no es el que demuestra todo lo que sabes de CSS moderno. Es el que llega, se entiende, se lee cómodamente y consigue que la persona haga lo que tiene que hacer sin obstáculos. Y si para eso hay que usar tablas HTML, que al menos sean tablas bien pensadas.

Diferencia entre transition y animation en CSS

Diferencia entre transition y animation en CSS

Cuando empezamos a añadir movimiento a una interfaz web, es muy habitual encontrarnos con dos propiedades que parecen hacer algo parecido: transition y animation. Ambas permiten animar elementos con CSS, ambas ayudan a que una interfaz se sienta más fluida y ambas pueden mejorar la experiencia de usuario cuando se usan con intención.

Pero aunque a simple vista puedan parecer intercambiables, no sirven exactamente para lo mismo.

La diferencia entre transition y animation en CSS está en cómo se activa el movimiento, cuánto control tenemos sobre los pasos intermedios y qué tipo de comportamiento queremos conseguir. Dicho de forma sencilla: una transition anima el cambio entre dos estados, mientras que una animation permite crear una secuencia de movimiento más completa mediante @keyframes.

Esta diferencia parece pequeña, pero en la práctica cambia mucho la forma de trabajar. No es lo mismo suavizar el cambio de color de un botón al hacer hover que crear un loader, una entrada animada de tarjetas, una ilustración en movimiento o un efecto que se repite en bucle.

En este artículo vamos a ver cuándo usar transition y cuándo usar animation en CSS, con ejemplos claros, comparaciones prácticas y recomendaciones para tomar mejores decisiones en proyectos reales.

Si estás empezando a trabajar con movimiento en interfaces, también puede resultarte útil complementar esta lectura con la guía de animaciones CSS para crear interfaces con más vida, donde se explican conceptos base para entender mejor cómo aplicar animaciones sin caer en el exceso.

Qué es una transition en CSS

Una transition en CSS permite animar el cambio de una propiedad cuando un elemento pasa de un estado a otro. Es decir, CSS detecta que una propiedad ha cambiado y, en lugar de aplicar ese cambio de golpe, lo interpola suavemente durante un tiempo determinado.

Por ejemplo, imagina un botón que cambia de color cuando el usuario pasa el ratón por encima. Sin transition, el color cambia de forma inmediata. Con transition, ese cambio se suaviza.

.button {
  background-color: #cc2b5e;
  color: white;
  transition: background-color 0.3s ease, transform 0.3s ease;
}

.button:hover {
  background-color: #753a88;
  transform: translateY(-2px);
}

En este caso, la transición se produce porque hay un cambio de estado: el botón pasa de su estado normal a su estado :hover.

La idea importante es esta: una transition necesita que algo cambie. Ese cambio puede estar provocado por una pseudoclase como :hover, :focus-visible o :active, por una clase añadida con JavaScript o por un cambio en el DOM.

Por eso las transiciones son tan habituales en botones, enlaces, campos de formulario, tarjetas interactivas, menús desplegables y otros componentes de interfaz.

Cómo funciona una transition

Una transición suele componerse de cuatro partes principales:

transition-property: background-color;
transition-duration: 0.3s;
transition-timing-function: ease;
transition-delay: 0s;

También podemos escribirlo en formato abreviado:

transition: background-color 0.3s ease 0s;
  • transition-property indica qué propiedad se va a animar.
  • transition-duration define cuánto tarda el cambio.
  • transition-timing-function controla el ritmo de la transición.
  • transition-delay añade un retraso antes de iniciar el efecto.
.card {
  opacity: 0.8;
  transform: scale(1);
  transition: opacity 0.25s ease, transform 0.25s ease;
}

.card:hover {
  opacity: 1;
  transform: scale(1.03);
}

Aquí estamos animando dos propiedades: opacity y transform. Ambas son buenas candidatas para animaciones porque suelen ofrecer buen rendimiento en navegador.

Cuándo usar transition CSS

Conviene usar transition cuando queremos animar un cambio simple entre dos estados. Es especialmente útil en elementos interactivos de una interfaz.

  • Botones que cambian de color al hacer hover.
  • Enlaces que muestran un subrayado suave.
  • Tarjetas que se elevan ligeramente al pasar el cursor.
  • Campos de formulario que cambian el borde al recibir foco.
  • Menús que se despliegan al añadir una clase.
  • Modales que aparecen con un cambio de opacidad.
.input {
  border: 2px solid #ddd;
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

.input:focus {
  border-color: #cc2b5e;
  box-shadow: 0 0 0 4px rgba(204, 43, 94, 0.15);
}

En este caso, la transición mejora la experiencia sin llamar demasiado la atención. El usuario entiende que el campo está activo, pero el efecto no compite con el contenido.

Este tipo de detalle es especialmente importante en componentes accesibles. Por ejemplo, cuando trabajamos estados de foco, conviene cuidar tanto el movimiento como la visibilidad del indicador. Si quieres profundizar en esta parte, puedes leer el artículo sobre focus visible y navegación con teclado.

Qué es una animation en CSS

Una animation en CSS permite definir una secuencia de movimiento usando @keyframes. A diferencia de transition, no se limita a pasar de un estado inicial a un estado final. Puede tener varios pasos intermedios, repetirse, alternarse, pausarse o ejecutarse automáticamente.

@keyframes float {
  0% {
    transform: translateY(0);
  }

  50% {
    transform: translateY(-12px);
  }

  100% {
    transform: translateY(0);
  }
}

.icon {
  animation: float 3s ease-in-out infinite;
}

Aquí no estamos esperando a que el usuario haga hover ni a que cambie una clase. La animación empieza por sí misma y se repite indefinidamente.

Este es uno de los puntos clave en la comparación transition vs animation CSS: las animaciones con @keyframes no necesitan necesariamente una interacción para ejecutarse. Pueden iniciarse al cargar la página, al añadir una clase, al entrar un elemento en pantalla o cuando lo decidamos mediante JavaScript.

Cómo funciona animation CSS

Una animación CSS suele componerse de dos partes. Primero, definimos los pasos de la animación con @keyframes:

@keyframes fadeInUp {
  from {
    opacity: 0;
    transform: translateY(24px);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

Después, aplicamos esa animación a un elemento:

.article-card {
  animation: fadeInUp 0.6s ease both;
}

La propiedad abreviada animation puede incluir varios valores:

animation: fadeInUp 0.6s ease 0.2s 1 normal both;

Ese código equivale, aproximadamente, a esto:

animation-name: fadeInUp;
animation-duration: 0.6s;
animation-timing-function: ease;
animation-delay: 0.2s;
animation-iteration-count: 1;
animation-direction: normal;
animation-fill-mode: both;

La propiedad animation-fill-mode es especialmente importante. Cuando usamos both, el elemento respeta los estilos del primer y último fotograma antes y después de ejecutarse la animación. Esto ayuda a evitar saltos visuales extraños.

Cuándo usar animation CSS

Conviene usar animation cuando necesitamos más control sobre el movimiento o cuando el efecto no depende únicamente de un cambio entre dos estados.

  • Loaders o spinners.
  • Elementos que entran en pantalla.
  • Ilustraciones animadas.
  • Efectos decorativos que se repiten.
  • Animaciones con varios pasos intermedios.
  • Microinteracciones más elaboradas.
  • Secuencias temporizadas.
  • Skeleton loaders.
  • Indicadores de atención, como un icono que pulsa suavemente.
@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

.loader {
  width: 32px;
  height: 32px;
  border: 4px solid #f8e0ea;
  border-top-color: #cc2b5e;
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}

Este sería un mal caso para transition, porque no hay realmente un cambio puntual entre dos estados. Queremos un movimiento continuo, repetitivo y autónomo. Ahí animation encaja mucho mejor.

Las animaciones también son muy útiles cuando trabajamos con ilustraciones CSS. Si te interesa este tipo de enfoque visual, puedes continuar con el artículo sobre cómo dibujar formas básicas con CSS o con la guía sobre pseudo-elementos en CSS para crear ilustraciones más complejas.

Diferencia entre transition y animation en CSS

La diferencia principal entre transition y animation en CSS puede resumirse así: transition anima un cambio de estado; animation define una secuencia de movimiento.

Una transición necesita que una propiedad cambie. Por ejemplo, un botón cambia su color en :hover. En cambio, una animación puede ejecutarse aunque no haya interacción del usuario, porque sus pasos están definidos dentro de @keyframes.

Comparativa rápida: transition vs animation CSS

Criteriotransitionanimation
Uso principalCambios simples entre dos estadosSecuencias de movimiento más complejas
Necesita cambio de estadoNo siempre
Usa @keyframesNo
Puede repetirse en bucleNo de forma naturalSí, con infinite
Control de pasos intermediosLimitadoAlto
Ideal para hover/focusNo suele ser necesario
Ideal para loadersNo
ComplejidadBajaMedia o alta
LegibilidadMuy directaRequiere más estructura

Esta tabla ayuda, pero no debería entenderse como una regla rígida. En CSS casi siempre hay varias formas de resolver un mismo efecto. Lo importante es elegir la herramienta que haga el código más claro, mantenible y coherente con la intención del movimiento.

Ejemplo comparativo con transition

Supongamos que queremos que una tarjeta se eleve cuando el usuario pasa el cursor por encima.

.card {
  transform: translateY(0);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08);
  transition: transform 0.25s ease, box-shadow 0.25s ease;
}

.card:hover {
  transform: translateY(-6px);
  box-shadow: 0 16px 36px rgba(0, 0, 0, 0.14);
}

Este es un caso perfecto para transition. Hay un estado inicial y un estado final. No necesitamos pasos intermedios. Tampoco necesitamos que la tarjeta se mueva sola. La interacción del usuario activa el cambio.

Ejemplo comparativo con animation

Ahora imaginemos que queremos que esa misma tarjeta aparezca suavemente al cargar la página.

@keyframes cardEntrance {
  0% {
    opacity: 0;
    transform: translateY(24px) scale(0.98);
  }

  60% {
    opacity: 1;
    transform: translateY(-4px) scale(1.01);
  }

  100% {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

.card {
  animation: cardEntrance 0.7s ease both;
}

Aquí animation tiene más sentido porque estamos creando una secuencia. La tarjeta no solo pasa de invisible a visible; tiene un pequeño movimiento intermedio que da sensación de entrada natural.

Cuándo usar transition y cuándo usar animation

La pregunta práctica no es solo qué diferencia hay entre ambas, sino cuándo conviene usar cada una. En proyectos reales, elegir bien evita código innecesario, mejora la experiencia de usuario y facilita el mantenimiento.

Usa transition para microinteracciones simples

Las transiciones son ideales para microinteracciones discretas. Por ejemplo, cuando un usuario interactúa con un botón, una tarjeta, un enlace o un campo de formulario.

.link {
  color: #753a88;
  text-decoration-color: transparent;
  transition: color 0.2s ease, text-decoration-color 0.2s ease;
}

.link:hover {
  color: #cc2b5e;
  text-decoration-color: currentColor;
}

Este tipo de efecto no necesita @keyframes. Sería excesivo crear una animación para algo tan simple.

Cuando ocurra esto, quiero que esta propiedad cambie suavemente.

Si esa frase describe lo que necesitas, probablemente estás ante un buen caso para usar transition.

Usa animation para movimientos autónomos o secuenciales

Las animaciones CSS son mejores cuando necesitas una secuencia con más intención. Por ejemplo, cuando un elemento entra, sale, vibra, rota, pulsa, flota o se repite.

@keyframes pulse {
  0%, 100% {
    transform: scale(1);
    opacity: 1;
  }

  50% {
    transform: scale(1.08);
    opacity: 0.75;
  }
}

.notification-dot {
  animation: pulse 1.5s ease-in-out infinite;
}

Este efecto sería incómodo de resolver con transition, porque no depende de un único cambio de estado. Queremos que el punto tenga vida propia y se repita.

Quiero que este elemento siga una secuencia de movimiento.

Si esa frase describe mejor tu intención, lo más probable es que necesites animation.

Regla sencilla para decidir

Una forma muy práctica de decidir es esta: si hay dos estados, normalmente usa transition. Si hay una secuencia, usa animation.

Si hay dos estados, usa transition

  • normal / hover
  • cerrado / abierto
  • visible / invisible
  • activo / inactivo
  • enfocado / no enfocado

Si hay una secuencia, usa animation

  • aparecer con rebote
  • rotar indefinidamente
  • parpadear varias veces
  • entrar desde abajo y estabilizarse
  • moverse siguiendo varios pasos
  • repetir un efecto decorativo

Propiedades animables: un detalle importante

No todas las propiedades CSS se animan igual de bien. Tanto con transition como con animation, es recomendable priorizar propiedades que el navegador pueda procesar de forma eficiente.

Las más recomendables suelen ser:

transform
opacity

También se pueden animar propiedades como background-color, color, border-color o box-shadow, aunque algunas pueden tener más coste visual o de rendimiento según el caso.

En cambio, conviene tener cuidado con propiedades que afectan al layout, como:

width
height
top
left
margin
padding

No significa que estén prohibidas, pero pueden provocar recalculado de layout y afectar al rendimiento, especialmente si hay muchos elementos en pantalla.

/* Menos recomendable */
.box {
  position: relative;
  top: 0;
  transition: top 0.3s ease;
}

.box:hover {
  top: -10px;
}

/* Más recomendable */
.box {
  transform: translateY(0);
  transition: transform 0.3s ease;
}

.box:hover {
  transform: translateY(-10px);
}

La segunda opción suele ser más fluida y predecible.

Este mismo criterio también se aplica cuando diseñamos efectos visuales más complejos. Si trabajas con composiciones CSS, fondos decorativos o ilustraciones adaptables, puedes complementar esta parte con el artículo sobre dibujar con CSS responsive.

Transition CSS con JavaScript: cambio de clases

Aunque muchas transiciones se activan con pseudoclases como :hover, también es muy común activarlas añadiendo o quitando clases con JavaScript.

.sidebar {
  transform: translateX(-100%);
  transition: transform 0.3s ease;
}

.sidebar.is-open {
  transform: translateX(0);
}
const sidebar = document.querySelector('.sidebar');
const button = document.querySelector('.menu-button');

button.addEventListener('click', () => {
  sidebar.classList.toggle('is-open');
});

Este patrón es muy útil porque mantiene la animación en CSS y deja a JavaScript solo la responsabilidad de cambiar el estado.

Aquí vuelve a encajar transition, porque el elemento tiene dos estados claros: cerrado y abierto.

Animation CSS con clases: controlar cuándo empieza

Las animaciones también pueden activarse mediante clases. Esto es útil cuando no queremos que una animación se ejecute siempre al cargar la página, sino en un momento concreto.

@keyframes reveal {
  from {
    opacity: 0;
    transform: translateY(16px);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.section {
  opacity: 0;
}

.section.is-visible {
  animation: reveal 0.6s ease both;
}

Este enfoque puede combinarse con IntersectionObserver para animar elementos cuando entran en el viewport.

const sections = document.querySelectorAll('.section');

const observer = new IntersectionObserver((entries) => {
  entries.forEach((entry) => {
    if (entry.isIntersecting) {
      entry.target.classList.add('is-visible');
    }
  });
});

sections.forEach((section) => observer.observe(section));

En este caso, animation tiene sentido porque queremos una entrada definida con @keyframes. Si la entrada fuera muy simple, una transición también podría servir.

Errores comunes al elegir entre transition y animation

A veces el problema no está en conocer las propiedades, sino en usarlas en el contexto equivocado. Veamos algunos errores frecuentes.

Usar animation para cualquier hover

Si solo quieres cambiar el color, la escala o la sombra de un botón al hacer hover, normalmente no necesitas animation.

/* Excesivo para un simple hover */
@keyframes buttonHover {
  from {
    transform: scale(1);
  }

  to {
    transform: scale(1.04);
  }
}

Sería más simple así:

.button {
  transform: scale(1);
  transition: transform 0.2s ease;
}

.button:hover {
  transform: scale(1.04);
}

Menos código, misma intención y mejor legibilidad.

Usar transition para un loader

Un loader necesita repetición. Por tanto, animation es mucho más adecuada.

@keyframes loading {
  to {
    transform: rotate(360deg);
  }
}

.loader {
  animation: loading 1s linear infinite;
}

Aquí una transición no sería natural, porque no hay un único cambio de estado que queramos suavizar.

Animar demasiadas cosas a la vez

El movimiento debe ayudar, no distraer. Una interfaz llena de elementos que se mueven constantemente puede aumentar la carga cognitiva y hacer que el usuario pierda el foco.

  • Para guiar la atención.
  • Para reforzar una acción.
  • Para comunicar cambio de estado.
  • Para hacer más comprensible una transición entre vistas.
  • Para dar sensación de continuidad.

Si la animación no aporta nada, probablemente sobra.

Accesibilidad: cuidado con el exceso de movimiento

Al hablar de transition CSS y animation CSS, es importante mencionar la accesibilidad. Algunas personas pueden experimentar molestias con animaciones intensas, movimientos bruscos, parpadeos o desplazamientos constantes.

CSS permite respetar la preferencia del usuario mediante prefers-reduced-motion.

@media (prefers-reduced-motion: reduce) {
  * {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

Este patrón reduce drásticamente el movimiento para usuarios que así lo han configurado en su sistema.

@media (prefers-reduced-motion: reduce) {
  .decorative-shape {
    animation: none;
  }

  .button {
    transition: none;
  }
}

No se trata de eliminar todo el diseño, sino de ofrecer una experiencia más cómoda. Una buena animación no debería ser imprescindible para entender la interfaz.

Además del movimiento, conviene cuidar el contraste, la jerarquía visual y la legibilidad. Si estás trabajando esta parte en tus interfaces, puedes revisar la guía sobre contraste y tipografía en accesibilidad visual.

Buenas prácticas para usar transition y animation en CSS

Mantén las transiciones breves

Las transiciones de interfaz suelen funcionar bien entre 150ms y 300ms. Si son demasiado rápidas, apenas se perciben. Si son demasiado lentas, la interfaz parece pesada.

.button {
  transition: transform 0.2s ease, background-color 0.2s ease;
}

Para cambios más complejos, como abrir un panel o mostrar un modal, puedes usar duraciones algo mayores, por ejemplo 300ms o 400ms.

Usa easing con intención

La función de tiempo cambia mucho la sensación del movimiento. ease suele funcionar bien para muchos casos, pero también puedes usar ease-in, ease-out, ease-in-out o cubic-bezier().

transition: transform 0.3s ease;
animation: fadeInUp 0.6s ease-out both;

Evita animaciones infinitas innecesarias

Las animaciones infinitas deben usarse con cuidado. Un loader tiene sentido porque comunica que algo está pasando. Pero un fondo lleno de elementos moviéndose sin parar puede distraer.

¿Este movimiento ayuda al usuario o solo decora?

Si solo decora, quizá deba ser muy sutil o no existir.

Nombra bien tus keyframes

Los nombres de @keyframes deberían describir la intención del movimiento.

@keyframes fadeInUp {}
@keyframes spin {}
@keyframes pulse {}
@keyframes slideInFromLeft {}

Evita nombres genéricos como animacion1, effect o move. Cuando el proyecto crece, los nombres claros facilitan mucho el mantenimiento.

Ejemplo final: usando transition y animation juntas

No siempre hay que elegir una u otra. De hecho, es muy común usar ambas en un mismo componente, cada una para una responsabilidad distinta.

Imaginemos una tarjeta que aparece al cargar y, además, tiene una interacción al hacer hover.

@keyframes cardReveal {
  from {
    opacity: 0;
    transform: translateY(20px);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.card {
  opacity: 0;
  transform: translateY(20px);
  animation: cardReveal 0.6s ease both;
  transition: box-shadow 0.25s ease, transform 0.25s ease;
}

.card:hover {
  transform: translateY(-4px);
  box-shadow: 0 16px 40px rgba(0, 0, 0, 0.12);
}

Aquí usamos animation para la entrada inicial y transition para la interacción posterior. La animación define cómo aparece la tarjeta; la transición suaviza cómo responde al usuario.

Este tipo de combinación es muy habitual en interfaces modernas. La clave está en no mezclar responsabilidades sin necesidad.

FAQs sobre transition vs animation CSS

¿Cuál es la principal diferencia entre transition y animation en CSS?

La principal diferencia es que transition anima el cambio entre dos estados, mientras que animation permite crear una secuencia de movimiento mediante @keyframes. Si quieres suavizar un hover, un focus o un cambio de clase, normalmente usarás transition. Si necesitas una animación con varios pasos, repetición o movimiento autónomo, usarás animation.

¿Es mejor usar transition o animation para mejorar el rendimiento?

No depende tanto de usar transition o animation, sino de qué propiedades estás animando. En general, transform y opacity suelen ser las opciones más recomendables para conseguir animaciones fluidas. En cambio, animar propiedades como width, height, top, left o margin puede ser más costoso porque afecta al layout.

¿Puedo usar transition y animation en el mismo elemento?

Sí, puedes usar ambas en el mismo elemento. Por ejemplo, puedes usar animation para que una tarjeta aparezca al cargar la página y transition para suavizar su comportamiento al hacer hover. Lo importante es que cada una tenga una función clara y que no entren en conflicto animando la misma propiedad al mismo tiempo.

Elegir bien el movimiento también es diseñar mejor

La diferencia entre transition y animation en CSS no es solo una cuestión técnica. También es una cuestión de diseño, experiencia de usuario y claridad de intención.

Una transition es perfecta cuando queremos que un cambio de estado se sienta más natural. Es directa, sencilla y muy útil para microinteracciones. Una animation, en cambio, nos da más control para crear secuencias, entradas, loaders, efectos decorativos o movimientos que se repiten.

La clave está en no elegir por costumbre. Antes de escribir CSS, conviene preguntarse qué queremos comunicar con ese movimiento. Si solo hay dos estados, probablemente una transición sea suficiente. Si hay una secuencia, varios pasos o repetición, entonces una animación será más adecuada.

En definitiva, transition y animation no compiten entre sí. Son herramientas complementarias. Usarlas bien permite crear interfaces más fluidas, más comprensibles y más agradables, sin caer en el exceso de movimiento ni complicar el código innecesariamente.