Qué hace morphing y qué solo se desvanece
Por qué un elemento se transforma y otro solo aparece, qué es realmente el morphing de la API, y cómo conseguir que dos elementos distintos se emparejen.
El efecto estrella de las transiciones de vista —una miniatura que crece hasta convertirse en la imagen de detalle— parece magia y es aritmética. Entender qué está pasando de verdad importa porque explica sus límites: por qué a veces se ve borroso, por qué a veces el contenido se estira mal, y por qué hay transformaciones que la API no puede hacer aunque lo parezca.
- Explicar qué anima el navegador cuando un elemento “hace morphing”.
- Predecir si dos elementos se van a emparejar o van a desvanecerse por separado.
- Corregir los artefactos de estiramiento con
object-fity con el tamaño de los pseudos. - Reconocer los casos donde el emparejamiento no es la técnica adecuada.
El morphing no es un morphing
Cuando un nombre existe en el estado antiguo y en el nuevo, el navegador genera dinámicamente una hoja de estilos con dos animaciones sobre el grupo de ese nombre:
widthyheightvan del tamaño de la caja de borde del elemento antiguo al del elemento nuevo.transformva de la transformación en espacio de pantalla del elemento antiguo a la del nuevo.
Eso es todo. Encima de esa caja que se mueve y se redimensiona, las dos capturas hacen un fundido cruzado. La combinación —una caja que se desplaza mientras su contenido cambia por fundido— es lo que el ojo lee como “un elemento se ha convertido en otro”.
Que la hoja de estilos sea generada dinámicamente tiene una consecuencia útil: los valores de esas animaciones se determinan en el instante en que empieza la transición, con la geometría real de los dos estados. No hay nada que calcular ni que ajustar a mano, y por eso el efecto funciona igual con cualquier layout.
Y tiene un límite que explica todos los artefactos: lo que se interpola es una caja, no una forma. No hay interpolación de contenido, ni de trazados, ni de texto. Si el elemento antiguo y el nuevo tienen proporciones muy distintas, la caja se deforma linealmente entre las dos y las dos imágenes se estiran con ella. Ese es el origen del efecto “goma” que se ve en transiciones entre un elemento cuadrado y uno muy alargado.
Cuándo se emparejan dos elementos
La regla es simple y no tiene excepciones: dos elementos se emparejan si comparten view-transition-name, uno en el estado antiguo y otro en el nuevo. No hace falta que sean el mismo nodo del DOM, ni que tengan la misma etiqueta, ni que estén en el mismo sitio del árbol. Solo el nombre.
De ahí salen los tres comportamientos posibles:
| Situación | Resultado |
|---|---|
| El nombre existe en los dos estados | Grupo con animación de geometría y fundido cruzado |
| El nombre existe solo en el estado antiguo | Grupo con solo old: se desvanece hacia fuera |
| El nombre existe solo en el estado nuevo | Grupo con solo new: se desvanece hacia dentro |
| El elemento no tiene nombre | Forma parte de la captura de root |
Esa cuarta fila es la que explica por qué “todo lo demás” hace un fundido: no es que se desvanezca individualmente, es que forma parte de una sola imagen grande, la del documento entero, que se funde con su versión nueva.
El caso más útil de la tabla es el segundo y el tercero combinados de forma deliberada. Un elemento que solo existe en el estado nuevo —un panel que aparece— tiene un grupo propio y puedes darle una entrada distinta del fundido, un deslizamiento por ejemplo, sin tocar nada más:
::view-transition-new(panel):only-child {
animation: entrar-desde-abajo 320ms cubic-bezier(0.2, 0, 0, 1) both;
}
@keyframes entrar-desde-abajo {
from { transform: translateY(100%); opacity: 0; }
}
Ese :only-child es el idioma que distingue “este pseudo está solo, no hay pareja” de “hay pareja y esto es una transformación”. Sin él, el mismo selector aplicaría también cuando el elemento sí tiene estado antiguo, y la animación de entrada se superpondría a la de geometría.
Los artefactos y cómo se arreglan
El estiramiento. Cuando las proporciones cambian, las capturas se deforman. La solución no está en el grupo sino en las imágenes: los pseudos old y new se comportan como contenido reemplazado y aceptan object-fit.
::view-transition-old(foto),
::view-transition-new(foto) {
object-fit: cover;
height: 100%;
width: 100%;
}
Con cover, la imagen mantiene sus proporciones y se recorta, que es lo que hace una foto real al cambiar de contenedor. Es la corrección que convierte un morphing de fotos de aceptable a bueno, y casi nunca aparece en los tutoriales.
El borrón. La captura antigua es un mapa de bits; si el grupo crece, se escala y se pixela. No hay forma de evitarlo, solo de disimularlo: un fundido cruzado que termine pronto oculta el estado antiguo mientras aún es pequeño. Si el cambio de tamaño es muy grande, conviene acortar la duración del old respecto a la del grupo:
::view-transition-old(foto) {
animation-duration: 120ms;
}
::view-transition-group(foto) {
animation-duration: 380ms;
}
El desajuste de esquinas. Si el elemento antiguo tiene border-radius y el nuevo no, el radio no se interpola: las capturas son mapas de bits con las esquinas ya recortadas, y durante la transición se ve el borde duro de la imagen nueva sobre la vieja redondeada. La corrección es aplicar el recorte al grupo, que sí es una caja viva:
::view-transition-group(foto) {
border-radius: 12px;
overflow: clip;
}
Con eso, las dos capturas quedan recortadas por el mismo radio durante toda la transición y el salto desaparece. Si además quieres que el radio cambie durante el recorrido, no lo hagas con animation-name en CSS: escribir animation-name sobre el grupo sustituye la animación de geometría que el navegador genera dinámicamente, y esa animación no tiene un nombre estable al que puedas referirte para volver a añadirla. La vía correcta es lanzar una animación adicional desde JavaScript tras ready, que se suma en lugar de sustituir:
const t = document.startViewTransition(mutacion);
t.ready.then(
() => {
document.documentElement.animate(
{ borderRadius: ['12px', '0px'] },
{ duration: 300, fill: 'both', pseudoElement: '::view-transition-group(foto)' }
);
},
() => {}
);
Aquí está la técnica que separa a quien usa la API de quien la entiende. Como el emparejamiento solo mira el nombre, puedes emparejar deliberadamente dos elementos completamente distintos para producir efectos que no tienen equivalente en ninguna otra API. Un botón de “añadir al carrito” que comparte nombre con el icono del carrito de la cabecera hace que el botón vuele hasta el icono y desaparezca dentro. Un elemento de la lista que comparte nombre con un mensaje de confirmación hace que la fila se convierta en el mensaje. Una imagen de portada que comparte nombre con el fondo de la página siguiente hace que el fondo herede el color de la portada. En ninguno de esos casos hay relación estructural entre los dos elementos: hay una relación narrativa, y el nombre es la forma de declararla. Ahora la advertencia, que es igual de importante: esto se agota rápido. Un emparejamiento arbitrario funciona cuando la conexión que sugiere es la que el usuario ya tiene en la cabeza —el producto va al carrito, la fila se convierte en la confirmación— y se convierte en ruido incomprensible cuando la conexión te la has inventado tú. El criterio para decidir: el morphing debe responder a una pregunta que el usuario se estaba haciendo —¿dónde ha ido esto?, ¿de dónde ha salido aquello?— y no a la pregunta de si queda bonito. Cuando no responde a ninguna pregunta, un fundido normal comunica mejor, porque no promete una relación que no existe.
Cuándo el emparejamiento no es la respuesta
Hay tres casos en que la gente intenta emparejar y no debería.
Cuando los dos elementos son visualmente idénticos y están en el mismo sitio. No hay nada que animar: el fundido cruzado de la raíz ya produce el resultado correcto, y nombrarlos solo añade coste.
Cuando el cambio es de contenido y no de posición. Un panel que cambia de texto no gana nada con un grupo propio: lo que quieres es un fundido de contenido, y eso se consigue desactivando la animación de geometría y dejando solo la de las imágenes.
Cuando hay muchos elementos y ninguno hace un recorrido significativo. Veinte tarjetas que se reordenan ligeramente producen veinte grupos cruzándose por la pantalla, y el resultado es visualmente caótico aunque cada movimiento individual sea correcto. La opción sobria —nombrar el contenedor y dejar que el interior se funda— comunica el mismo cambio con la décima parte del ruido y del coste.