Cómo animar una transición de modo oscuro con fluidez
Aprende a animar el cambio entre tema claro y oscuro: evitar el error de transition: all, revelado circular con View Transitions API y prevención de parpadeos.
Idea clave
Animar el modo oscuro requiere equilibrar la suavidad visual con el rendimiento. Evita colocar transition: all * en CSS, ya que provoca recalcular todos los estilos de la página y genera tirones graves. Utiliza en su lugar la View Transitions API para un revelado circular centrado en el botón de alternancia, o limita las transiciones CSS a background-color y color en elementos clave con una duración de 200 a 300 ms.
El error común de transition: all en todo el DOM
Aplicar transition: all 0.3s a todos los elementos (*) obliga al navegador a recalcular dimensiones, sombras, bordes y tipografías en cada nodo del DOM a la vez. En páginas complejas esto provoca caídas drásticas de fotogramas. Transiciona únicamente las variables CSS de color y fondo en el elemento raíz.
El revelado circular con View Transitions API
Los navegadores modernos soportan document.startViewTransition(). Permite crear una máscara circular animada con clip-path que se expande desde el punto exacto donde el usuario pulsó el interruptor, revelando el nuevo tema como una onda suave.
- Evita transicionar propiedades que desencadenen reflujo de diseño
- Usa document.startViewTransition() con animación de clip-path circular
- Almacena la preferencia en localStorage y aplica la clase antes de pintar el DOM
- Mantén la duración entre 250 y 350 ms para no retrasar la lectura
Prevención del parpadeo de tema no estilizado (FOUC)
Si el usuario tiene activado el modo oscuro en su sistema o guardado en almacenamiento local, aplica la clase del tema en un script bloqueante en la cabecera del documento antes de renderizar el cuerpo de la página para evitar destellos blancos.
Accesibilidad y fotosensibilidad
Los cambios bruscos de contraste alto a bajo pueden molestar a personas con sensibilidad a la luz. Si el usuario solicita prefers-reduced-motion, realiza el cambio de tema de inmediato sin transiciones expansivas ni ondas circulares.
Fragmento de implementación en producción
/* View Transitions API circular reveal */
::view-transition-old(root),
::view-transition-new(root) {
animation: none;
mix-blend-mode: normal;
}
::view-transition-new(root) {
animation: reveal-theme 400ms ease-out;
}
@keyframes reveal-theme {
from { clip-path: circle(0% at var(--click-x) var(--click-y)); }
to { clip-path: circle(150% at var(--click-x) var(--click-y)); }
}Principios clave para recordar
- Nunca uses transition: all en todos los elementos del DOM
- Implementa View Transitions API para revelados circulares elegantes
- Aplica el tema guardado en el encabezado para evitar parpadeos blancos
- Cambia el tema de forma instantánea ante movimiento reducido
Preguntas frecuentes
Fuentes
- View Transitions API — W3C
- Smooth theme transitions with View Transitions — Chrome Developers