Animación CSS avanzada con Claude Code: rendimiento, accesibilidad y pruebas
Guía práctica para crear animaciones CSS rápidas, accesibles y verificables con Claude Code.
La animación CSS necesita intención, no solo movimiento
Claude Code puede generar un fade, un slide o un skeleton en segundos. El reto aparece cuando esa animación llega a producción: debe explicar qué cambió, no distraer; debe sentirse rápida, no pesada; y debe respetar a quienes han configurado el sistema para reducir movimiento.
Esta guía se centra en implementación. Veremos cuándo usar transition y cuándo keyframes, por qué transform y opacity suelen ser las propiedades más seguras, qué es layout thrash, cómo aplicar prefers-reduced-motion, cómo diseñar animaciones de entrada y vinculadas al scroll, cuándo usar skeleton states, cómo convertir el movimiento en tokens de diseño, cómo pedir una revisión crítica a Claude Code y cómo comprobar el resultado con Playwright.
Definiciones rápidas: transition es una interpolación entre dos estados, por ejemplo un botón en hover. Keyframes es una línea de tiempo con pasos como 0%, 60% y 100%. Layout thrash ocurre cuando el navegador recalcula tamaño y posición muchas veces por cambios de CSS o JavaScript. Los tokens de movimiento son valores con nombre, como --motion-duration-fast, para mantener duración, easing y distancia de forma consistente.
Para completar el contexto, revisa también optimización de rendimiento con Claude Code, variables CSS con Claude Code y accesibilidad con Claude Code.
Elegir bien entre transition y keyframes
Usa transitions para cambios pequeños de estado: hover, focus, active, selected, expanded o disabled. Usa keyframes cuando el recorrido intermedio importa: entrada de un panel, bucles de carga, avisos por etapas, progreso de lectura o reveal al hacer scroll.
Conviene decirle esto a Claude Code desde el prompt. Si solo pides “hazlo más animado”, puede generar reglas que animen top, left, height o margin. Esas propiedades pueden forzar recalculos de layout y producir tirones. Una instrucción más precisa es: usa transition para estados interactivos, keyframes para movimiento con línea de tiempo y prioriza transform y opacity.
:root {
--motion-duration-fast: 160ms;
--motion-duration-normal: 280ms;
--motion-ease-standard: cubic-bezier(0.2, 0, 0, 1);
--motion-distance-sm: 12px;
}
.button {
transition:
background-color var(--motion-duration-fast) var(--motion-ease-standard),
transform var(--motion-duration-fast) var(--motion-ease-standard);
}
.button:hover {
transform: translateY(-2px);
}
.notice {
opacity: 0;
transform: translateY(var(--motion-distance-sm));
animation: notice-enter var(--motion-duration-normal) var(--motion-ease-standard) forwards;
}
@keyframes notice-enter {
from {
opacity: 0;
transform: translateY(var(--motion-distance-sm));
}
to {
opacity: 1;
transform: translateY(0);
}
}
El botón usa transition porque responde a un estado directo. El aviso usa keyframes porque tiene una entrada diseñada. Para confirmar sintaxis y comportamiento, las referencias oficiales de MDN sobre CSS animations y transform son el punto de partida.
Rendimiento: empieza por transform y opacity
El navegador genera cada frame pasando por layout, paint y composición. Layout calcula geometría; paint dibuja píxeles; composición combina capas. Animar transform y opacity suele quedarse en composición, por eso tiende a ser más fluido que modificar geometría.
Animar width, height, margin, top o left puede afectar a elementos vecinos. Si además JavaScript lee medidas y escribe estilos en bucle, aparece layout thrash. En componentes React, la clase de animación debe ser simple, explícita y fácil de probar.
import type { ReactNode } from "react";
import "./motion.css";
type AnimatedPanelProps = {
children: ReactNode;
isOpen: boolean;
};
export function AnimatedPanel({ children, isOpen }: AnimatedPanelProps) {
return (
<section
className={isOpen ? "panel panel-enter" : "panel"}
aria-hidden={!isOpen}
>
{children}
</section>
);
}
.panel {
opacity: 0;
transform: translateY(12px) scale(0.98);
pointer-events: none;
}
.panel-enter {
animation: panel-enter 220ms cubic-bezier(0.2, 0, 0, 1) forwards;
pointer-events: auto;
}
@keyframes panel-enter {
to {
opacity: 1;
transform: translateY(0) scale(1);
}
}
No abuses de will-change. Puede ayudar si se aplica justo antes de animar, pero mantenerlo en muchos elementos consume memoria. La guía de web.dev sobre rendimiento de animaciones explica por qué la elección de propiedades es más importante que añadir pistas al navegador sin criterio.
Casos de uso reales
Primer caso: entrada de tarjetas, tablas de precios o módulos de dashboard. Una aparición breve guía la mirada. Una cascada lenta en todas las tarjetas solo retrasa la lectura. Mantén los delays pequeños y asegúrate de que el contenido sea visible si la animación no se ejecuta.
Segundo caso: feedback vinculado al scroll, como una barra de progreso de lectura o la aparición de secciones. CSS animation-timeline es útil, pero debe degradar bien. Si el navegador no lo soporta, el contenido debe seguir visible.
.scroll-progress {
position: fixed;
inset: 0 auto auto 0;
z-index: 20;
width: 100%;
height: 3px;
transform-origin: left;
transform: scaleX(0);
background: var(--color-accent, #2563eb);
}
@supports (animation-timeline: scroll()) {
.scroll-progress {
animation: progress-grow linear both;
animation-timeline: scroll();
}
}
@keyframes progress-grow {
to {
transform: scaleX(1);
}
}
.reveal {
opacity: 1;
transform: none;
}
@supports (animation-timeline: view()) {
.reveal {
opacity: 0;
transform: translateY(16px);
animation: reveal-up 1ms linear both;
animation-timeline: view();
animation-range: entry 10% cover 30%;
}
}
@keyframes reveal-up {
to {
opacity: 1;
transform: translateY(0);
}
}
Tercer caso: skeleton y estados de carga. Un skeleton reduce incertidumbre, pero un shimmer fuerte durante mucho tiempo cansa. Si una operación dura varios segundos, añade texto de estado, reintento o cancelación.
Cuarto caso: feedback operativo en SaaS. Guardado completado, filtro aplicado, elemento movido o panel de error abierto pueden beneficiarse de una animación corta. En pantallas de trabajo repetitivo, la estabilidad vale más que el espectáculo.
Respetar reduced motion y saber cuándo no animar
prefers-reduced-motion permite responder a la preferencia del usuario por menos movimiento. No es un detalle opcional: algunas personas sienten mareo, fatiga o distracción con animaciones intensas. La referencia oficial de MDN sobre prefers-reduced-motion incluye ejemplos claros.
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
scroll-behavior: auto !important;
animation-duration: 1ms !important;
animation-delay: 0ms !important;
animation-iteration-count: 1 !important;
transition-duration: 1ms !important;
}
.scroll-progress {
animation: none;
transform: scaleX(1);
}
.skeleton {
animation: none;
background-image: none;
}
}
También hay situaciones donde no conviene animar: confirmaciones de pago, textos legales, errores críticos de formulario, lectura larga, tablas densas y menús usados muchas veces al día. En esos casos, la prioridad es claridad inmediata.
Pedir a Claude Code una revisión crítica
No pidas solo “añade animación”. Pide que revise riesgos. Este prompt funciona como checklist:
Review and improve the CSS animation implementation for this UI.
Requirements:
- Use transition for simple hover/focus/open states.
- Use keyframes only when intermediate timing matters.
- Animate transform and opacity first; avoid top, left, width, height, and margin animations.
- Add design tokens for duration, easing, and distance.
- Respect prefers-reduced-motion.
- Keep content visible when scroll-linked animation is unsupported.
- Do not animate critical form errors, payment confirmation, or long reading content.
Return:
1. Risky selectors and why they are risky.
2. A corrected CSS/React implementation.
3. Manual and Playwright checks to verify overflow and reduced motion.
Con esto Claude Code buscará layout thrash, bucles infinitos, uso excesivo de will-change, falta de fallback y preferencias de movimiento ignoradas.
Verificar con Playwright
Las fallas de animación suelen ser visuales. Añade pruebas enfocadas para overflow horizontal, visibilidad del contenido y comportamiento con reduced motion.
import { expect, test } from "@playwright/test";
test("animated page has no horizontal overflow", async ({ page }) => {
await page.goto("/animation-demo");
const overflow = await page.evaluate(() => {
return document.documentElement.scrollWidth > window.innerWidth;
});
expect(overflow).toBe(false);
});
test("reduced motion keeps content visible", async ({ browser }) => {
const context = await browser.newContext({ reducedMotion: "reduce" });
const page = await context.newPage();
await page.goto("/animation-demo");
await expect(page.locator(".reveal").first()).toBeVisible();
await expect(page.locator(".skeleton").first()).toHaveCSS("animation-name", "none");
await context.close();
});
En interfaces críticas, añade comparación de capturas en escritorio y móvil. Las pruebas no juzgan el gusto visual, pero detectan contenido oculto, scroll horizontal y preferencias de movimiento ignoradas.
Resumen y siguiente paso
La animación CSS de producción empieza por una intención clara. Usa transition para cambios simples, keyframes para líneas de tiempo, transform y opacity para movimiento fluido, tokens para consistencia, reduced motion para accesibilidad y Playwright para verificación. Claude Code funciona mejor cuando recibe esas restricciones.
Como siguiente paso, elige una lista de tarjetas o una sección CTA existente y aplica los tokens, la animación de entrada, la regla reduced motion y las pruebas de este artículo. Para una revisión más completa, consulta formación y consultoría.
Nota de verificación práctica: al limitar el movimiento a transform y opacity, no apareció overflow horizontal. En Playwright con reduced motion, el contenido .reveal siguió visible y el skeleton quedó sin animación. En pantallas operativas, el shimmer largo se sintió más lento, así que conviene usar placeholders más discretos.
PDF gratis: cheatsheet de Claude Code
Introduce tu email y descarga una hoja con comandos, hábitos de revisión y flujos seguros.
Cuidamos tus datos y no enviamos spam.
Sobre el autor
Masa
Ingeniero enfocado en workflows prácticos con Claude Code.
Artículos relacionados
Permission receipt para Claude Code: alcance, prueba y rollback
Patrón de permission receipt para Claude Code: acciones permitidas, aprobación, pruebas, rollback y CTA de ingresos.
Agent Harness seguro para Claude Code y Codex: permisos, verificacion y rollback
Diseña un Agent Harness seguro para Claude Code y Codex con permisos, plan, verificaciones y rollback.
Subagentes de Claude Code: guía práctica para delegar trabajo de forma segura
Guía práctica de subagentes en Claude Code para dividir artículos y código: reglas, prompts, riesgos y checklist.