View Transitions
View Transitions
6 reglasProgressive enhancement obligatorio
La View Transitions API no esta disponible en todos los browsers. El código debe funcionar identicamente sin transiciones cuando la API no existe. El patrón correcto: envolver la navegación en if (document.startViewTransition) y usar la navegación nativa como fallback. Nunca requerir la API para que la navegación funcione, es una mejora, no un requisito.
link.addEventListener('click', async (e) => {
e.preventDefault();
const updateDOM = () => navigate(link.href);
if (document.startViewTransition) {
document.startViewTransition(() => updateDOM());
} else {
updateDOM();
}
});
// Sin fallback
link.addEventListener('click', async (e) => {
e.preventDefault();
await document.startViewTransition(
async () => navigate(link.href)
);
// Firefox: "startViewTransition is not a function"
});
Morph de elementos: view-transition-name
Asignar view-transition-name a un elemento en la vista de origen y el mismo nombre al elemento correspondiente en la vista de destino hace que el browser anime automáticamente la posición, tamaño y forma entre los dos estados. Es el efecto "hero transition" de iOS nativo en el web. El nombre debe ser único en el documento, dos elementos con el mismo nombre en la misma vista cancelan la transición.
::view-transition-old(product-image) {
animation: fade-out 0.25s ease;
}
::view-transition-new(product-image) {
animation: fade-in 0.25s ease;
}
Cross-document transitions opt-in
Las View Transitions entre documentos distintos (navegación MPA normal) requieren que ambas páginas declaren @view-transition { navigation: auto; } en su CSS. Basta con que una página lo omita para que la transición no ocurra. Añadir la declaración en el CSS global del layout garantiza cobertura completa. Verificar en Chrome 126+, no disponible en otros browsers aún.
@view-transition {
navigation: auto;
}
/* Todas las páginas tienen opt-in */
Reduced-motion: desactiva o simplifica
Con prefers-reduced-motion: reduce, la View Transition debe simplificarse a un fade instantaneo (100ms) o desactivarse por completo. No simplemente "reducir" la velocidad, algunos usuarios tienen vestibular disorders y cualquier movimiento puede causar malestar. La transición reducida no es un subconjunto del diseño animado: es un diseño alternativo con cero movimiento lateral o de escala.
@media (prefers-reduced-motion: reduce) {
::view-transition-group(*) {
animation-duration: 0s;
}
/* O simplificar a crossfade corto: */
::view-transition-old(root),
::view-transition-new(root) {
animation: none !important;
mix-blend-mode: normal;
}
}
/* Solo reduce la velocidad */
@media (prefers-reduced-motion: reduce) {
::view-transition-group(*) {
animation-duration: 600ms;
/* slide y scale siguen activos */
}
}
Cuando NO usar View Transitions
View Transitions no son apropiadas para todas las interacciones. Usarlas en form submissions, error states, tab switches dentro de la misma página o modal open/close hace que la interfaz se sienta lenta y teatral. La API toma un snapshot del DOM antes de animar, lo que agrega latencia a acciones que deberan sentirse instantaneas. Reservar View Transitions para navegación entre páginas, transiciones lista-a-detalle y cambios de layout significativos. Para micro-interacciones dentro de la misma vista, CSS transitions y animations son más rápidas y apropiadas.
chrome developers · nngroupPerformance: snapshot rápida, DOM pesado no
La View Transitions API toma un screenshot del estado actual del DOM antes de animar. Si el DOM tiene miles de nodos o animaciones CSS corriendo, el snapshot puede tardar 100-300ms y percibirse como freeze. Contener la transición a un subárbol específico con view-transition-name en solo el elemento que cambia (no la página entera) reduce el snapshot de cientos de milisegundos a menos de 15ms. Verificar con performance.mark que el snapshot ocurra en menos de 100ms.
.content-panel {
view-transition-name: panel;
}
document.startViewTransition(() => {
updatePanel(newContent);
});
// snapshot solo del subtree
navigate(href);
});
// snapshot captura TODO el DOM