Fecha de publicación: 28 de agosto de 2025
La Búsqueda de Google tiene uno de los alcances más grandes del mundo, por lo que los cambios en nuestra experiencia del usuario pueden tener un impacto en miles de millones de usuarios. Siempre soñamos con una experiencia web que se sintiera más moderna y similar a una app. Cuando comenzamos a desarrollar el Modo IA, queríamos crear una experiencia para nuestros usuarios en la que la transición del modo de búsqueda estándar al Modo IA se sintiera fluida y conectada. Cuando escuchamos hablar de las transiciones de vista entre documentos, supimos que eran el complemento perfecto para la función. En este caso de éxito, se comparte lo que aprendimos al agregar la función de transición junto con el lanzamiento del Modo IA.
Las transiciones de vista entre documentos son un gran avance en lo que respecta a las herramientas nativas del navegador, y nos entusiasma ver cómo darán forma a la Web en el futuro.
Cambiar el statu quo
La Búsqueda de Google tiene requisitos estrictos y conservadores de compatibilidad con navegadores. Por lo general, usar una función de disponibilidad limitada estaba prohibido. En el caso de las transiciones de vista entre documentos, descubrimos que un polyfill no era viable, ya que el principal obstáculo era que no había una API de instantáneas de píxeles y clonar toda la ventana gráfica generaba problemas de rendimiento importantes. Por lo tanto, usar la función como una mejora progresiva fue la mejor manera de lanzarla junto con el Modo IA. Dado que las animaciones creadas por las transiciones de vista no afectan directamente la funcionalidad del sitio web, para el tráfico no compatible, simplemente se inhabilitarían, lo que ya era el estado de producción actual sin animaciones de transición.
Primero probamos esta estrategia de mejora progresiva con nuestros usuarios internos. Esto nos proporcionó comentarios iniciales, que fueron abrumadoramente positivos. Los comentarios recibidos también revelaron errores, incluidos problemas de rendimiento e interacciones no deseadas con otras funciones, como contextos de apilamiento superpuestos.
Descubrimos que esta estrategia es exitosa y creo que la probaremos con otras funciones nuevas del navegador en el futuro.
Dificultades que encontramos y cómo las resolvimos
Latencia, bloqueo de renderización y temporizadores de vigilancia
En general, la latencia adicional que se genera con las transiciones de vistas de MPA es insignificante para el 99% de los casos de uso, en especial en el hardware moderno. Sin embargo, la Búsqueda de Google tiene un estándar extremadamente alto en lo que respecta a la latencia, y nos esforzamos por crear experiencias del usuario que funcionen bien en todos los dispositivos. Para nosotros, incluso unos pocos milisegundos adicionales son importantes, por lo que tuvimos que invertir en la forma de implementar correctamente las transiciones de vista entre documentos sin perjudicar la experiencia del usuario.
El bloqueo de la renderización es una técnica que se combina bien con las transiciones de vista entre documentos. Las instantáneas de seudoelementos del documento entrante solo pueden mostrar contenido que ya se haya renderizado. Por lo tanto, para animar el contenido del documento entrante, debes renderizar el bloque hasta que se renderice el elemento objetivo que deseas animar. Para ello, usa el atributo blocking
en un HTMLLinkElement
. El bloqueo de la renderización tiene sus inconvenientes, ya que esperar un elemento que se encuentra hacia el final del árbol DOM del documento entrante puede tener un impacto considerable en la latencia. Tuvimos que equilibrar esta compensación de manera adecuada y solo renderizar el bloqueo en los elementos que se renderizan muy temprano en el ciclo de vida de la página.
<!-- Link tag in the <head> of the incoming document -->
<link blocking="render" href="#target-id" rel="expect">
<!-- Element you want to animate in the <body> of the incoming document -->
<div id="target-id">
some content
</div>
En algunos casos, no era suficiente ser preciso sobre el elemento en el que renderizabas el bloque. Algunos dispositivos o conexiones seguirían viendo latencia agregada incluso cuando se bloquea la renderización en un elemento cerca del comienzo del árbol DOM. Para controlar esos casos, escribimos una secuencia de comandos de temporizador de vigilancia para quitar el HTMLLinkElement
después de que transcurre una cierta cantidad de tiempo para forzar el desbloqueo de la renderización del documento entrante.
Una forma sencilla de hacerlo es la siguiente:
function unblockRendering() {
const renderBlockingElements = document.querySelectorAll(
'link[blocking=render]',
);
for (const element of renderBlockingElements) {
element.remove();
}
}
const timeToUnblockRendering = t - performance.now();
if (timeToUnblockRendering > 0) {
setTimeout(unblockRendering, timeToUnblockRendering);
} else {
unblockRendering();
}
Limitaciones de cobertura
Otro problema que encontramos es que la regla @ de transiciones de vista entre documentos navigation: auto
ocurre a nivel global dentro del documento. No hay una forma integrada de limitar el alcance de la habilitación de las transiciones de vista entre documentos solo a objetivos de clic específicos. Dado que se trata de un cambio tan grande, no pudimos habilitar las transiciones de vista entre documentos en el 100% de las navegaciones en la Búsqueda de Google. Necesitábamos una forma de habilitar o inhabilitar de forma dinámica las transiciones de vista entre documentos según la función con la que interactuaba el usuario. En nuestro caso, solo las habilitamos para los cambios de modo hacia y desde el Modo IA. Para ello, actualizamos de forma programática la regla @navigation según el destino en el que se hizo clic o se presionó.
Una forma de activar o desactivar la regla @ de transición de vista es la siguiente:
let viewTransitionAtRule: HTMLElement | undefined;
const DISABLED_VIEW_TRANSITION = '@view-transition{navigation:none;}';
const ENABLED_VIEW_TRANSITION = '@view-transition{navigation:auto;}';
function getVtAtRule(): HTMLElement {
if (!viewTransitionAtRule) {
viewTransitionAtRule = document.createElement('style');
document.head.append(viewTransitionAtRule);
}
return viewTransitionAtRule;
}
function disableVt() {
getVtAtRule().textContent = DISABLED_VIEW_TRANSITION;
}
function enableVt() {
getVtAtRule().textContent = ENABLED_VIEW_TRANSITION;
}
Bloqueos y animaciones compuestas
Algunas de las animaciones generadas automáticamente en los seudoelementos de transición de vista provocaron pérdidas de fotogramas en dispositivos más antiguos, lo que perjudicó la experiencia limpia y fluida que queremos ofrecer a los usuarios. Para mejorar el rendimiento de las animaciones, las volvimos a escribir con técnicas de animación que se pueden ejecutar en el compositor. Pudimos hacerlo inspeccionando los fotogramas clave para obtener las dimensiones de los seudoelementos de instantánea antes y después, y usando cálculos matriciales para reescribir los fotogramas clave según corresponda. En el siguiente ejemplo, se muestra cómo tomar la animación de cada seudoelemento de transición de vista:
const pseudoElement = `::view-transition-group(${name})`;
const animation = document
.getAnimations()
.find(
(animation) =>
(animation.effect as KeyframeEffect)?.pseudoElement === pseudoElement,
);
Obtén más información para escribir fotogramas clave de transiciones de vistas eficaces en View Transitions Applied: Dealing with the Snapshot Containing Block.
Otros aspectos que debes tener en cuenta
Uno de los problemas más destacados es que etiquetar elementos con la propiedad view-transition-name
de CSS afecta el contexto de apilamiento (Especificación de transiciones de vista: Sección 2.1.1). Esta fue la fuente de varios errores que requirieron la modificación del z-index
de los elementos del contenedor.
Otra cosa que debes tener en cuenta es que, de forma predeterminada, es posible que no desees agregar valores de view-transition-name
a los elementos. Muchas personas trabajan en la Búsqueda de Google. Para evitar que los valores de view-transition-name
que establece nuestro equipo en los elementos entren en conflicto con los valores que podrían usar personas de otros equipos, utilizamos tipos de transición de vista para agregar de forma condicional la propiedad view-transition-name
solo mientras está activo un tipo de transición de vista específico.
Ejemplo de CSS para agregar el view-transition-name
de the-element
a un elemento solo cuando el tipo de transición de vista de ai-mode
está activo:
html:active-view-transition-type(ai-mode) {
#target {
view-transition-name: the-element;
}
}
Una vez que tengas estas reglas de CSS para todas tus transiciones de vista, podrás cambiar de forma dinámica el tipo de transición de vista actual para cualquier navegación durante los eventos pageswap
y pagereveal
.
Ejemplo de actualización del tipo de transición de vista a ai-mode
durante el evento pageswap
.
function updateViewTransitionTypes(
event: ViewTransitionEvent,
types: string[],
): void {
event.viewTransition.types.clear();
for (const type of types) {
event.viewTransition.types.add(type);
}
}
window.addEventListener(
'pageswap',
(e) => {
updateViewTransitionTypes(
e as ViewTransitionEvent,
['ai-mode'],
);
}
);
De esta manera, evitamos colisiones de nombres y no creamos instantáneas innecesarias de elementos que no necesitan crearse como parte de la transición hacia el Modo IA y desde él.
Por último, los problemas de contexto de apilamiento solo estarían presentes durante la transición de vista. Para resolver esos problemas, podemos orientar los índices Z de los seudoelementos generados, en lugar de modificar de forma arbitraria los índices Z de los elementos originales solo para resolver este problema cuando se usan transiciones de vista.
::view-transition-group(the-element) {
z-index: 100;
}
¿Qué sigue?
Tenemos planes para usar transiciones de vista entre documentos en la Búsqueda de Google, incluida la integración con la API de Navigation una vez que esté disponible en todos los navegadores. Mantente al tanto para ver qué crearemos a continuación.