Volver al Blog
Huella digital

Eventos de cambio de viewport en móvil: orden y medida

El teclado, la orientación y la barra del navegador redimensionan el viewport. Ordena los eventos, agrápalos en un frame y decide el layout una vez por cambio.

BotBrowser Team

Eventos de cambio de viewport en móvil: orden y medida
Documentación

Quieres la documentación estructurada de Huella digital?

Este artículo forma parte de la biblioteca editorial. Para pasos de configuración, material de referencia y actualizaciones continuas, entra en la sección de docs.

En un escritorio, un cambio de viewport es un evento. En un teléfono es una secuencia: se abre el teclado, se retira la barra del navegador, gira el dispositivo, y cada uno produce un evento distinto con una geometría distinta. Esa secuencia es la que decide si un layout aguanta, y empieza donde termina la guía de propiedades de pantalla y viewport: una vez sabido qué propiedad responde a qué pregunta, el problema siguiente es ordenar los eventos que las cambian.

BotBrowser puede cargar una página propia con un tamaño de viewport y una relación de píxeles declarados en un contexto controlado y registrar lo que la página observa; no simula todas las animaciones de teclado de un teléfono real, no hace que un navegador móvil reporte otra altura de barra a demanda y no sustituye la prueba en las clases de dispositivo que tus usuarios tienen.

Orden de cambio del viewport visual en móvil

Resumen

  • Trata cada cambio de viewport móvil como una secuencia y no como un resize único.
  • Lee window.visualViewport para el área visible y window.innerWidth para el área de layout, y registra ambas.
  • Agrupa las llamadas de resize en un frame antes de medir.
  • Decide el layout una vez por cambio y anota lo que la página observó.

Contenido

Qué cambia cuando cambia el teléfono

Un navegador móvil tiene más de un viewport, y se mueven en momentos distintos. El viewport de layout es el área contra la que la página maqueta, y cambia cuando aparece o se retira la barra del navegador. El viewport visual es la parte que el usuario realmente ve, y también cambia cuando se abre el teclado, cuando hay zoom con dos dedos y cuando un gesto de desplazamiento ocupa más espacio que el viewport de layout.

window.innerWidth y window.innerHeight informan del viewport de layout en píxeles CSS. window.visualViewport informa del visual con width, height, offsetTop, offsetLeft, scale y pageTop. Cada uno de esos números puede cambiar de forma independiente, y por eso un layout que reacciona a uno y supone constantes los demás falla de una manera que parece intermitente; la guía de propiedades de pantalla y viewport nombra qué propiedad responde a qué pregunta.

window.screen es una tercera vista en la que los dos no coinciden: la pantalla informa del área disponible del dispositivo, que en un teléfono puede no cambiar mientras el viewport cambia varias veces durante una interacción con el teclado. Decidir el layout con screen.height es una fuente habitual de layouts correctos al cargar y rotos tras girar.

La relación de píxeles es un cuarto valor y puede cambiar sin evento de resize. Un navegador puede ajustarla cuando la página pasa entre pantallas o cuando el usuario cambia el escalado de texto. Un canvas dimensionado una vez al cargar se verá bien hasta que ocurra una de esas dos cosas, y entonces se verá borroso o demasiado nítido sin que haya saltado ningún listener.

Ordenar los eventos

Al abrir el teclado, normalmente cambia primero el viewport visual, y la política de relación de píxeles describe el caso en que la relación cambia sin resize, luego el de layout y después el navegador puede desplazar el elemento enfocado a la vista. El orden exacto no está garantizado entre navegadores, y ahí está el punto: un handler que supone un orden fijo leerá de vez en cuando un valor obsoleto de uno de los dos.

El enfoque fiable es escuchar a la vez el resize de window.visualViewport y el de la ventana, y tratar la pareja como una sola señal. Registra listeners en visualViewport para resize y scroll, y en la ventana para resize y orientationchange, y haz que todos pasen por la misma función de planificación. Esa función mide una vez, en el frame siguiente, con los valores que estén vigentes en ese momento.

El cambio de orientación es el caso que más se escapa. En muchos teléfonos el resize de la ventana ocurre antes de que se invierta la media query de orientación, así que un handler que lee matchMedia('(orientation: portrait)') dentro del callback de resize puede ver la orientación anterior. Leer la orientación en el frame siguiente, a partir de la proporción del viewport visual, evita depender del momento en que se actualiza la media query.

La animación de la barra del navegador genera resize rápidos. Cuando la barra de direcciones se retira al hacer scroll, pueden dispararse varios eventos en pocos cientos de milisegundos, cada uno con una altura algo distinta. Medir y maquetar en cada uno produce un traqueteo visible en un dispositivo de gama media. Agruparlos en un solo frame no es una optimización solo para equipos lentos: es lo que evita que el layout siga la animación y luego salte hacia atrás.

El zoom es el caso en que cambia el viewport visual y no el de layout, y donde visualViewport.scale es el valor a registrar. Un elemento con position: fixed queda anclado al viewport de layout, lo que durante el zoom puede dejarlo fuera de lo que el usuario ve. Un elemento que debe seguir el área visible tiene que compensar con visualViewport.offsetTop y offsetLeft en lugar de suponer que la posición fija sigue al dedo.

Medir en un frame

El patrón de planificación es lo bastante corto para escribirlo una vez y reutilizarlo. Guarda una bandera pendiente, registra un callback con requestAnimationFrame si no hay ninguno pendiente y dentro del callback limpia la bandera y lee en el mismo tick todos los valores de los que depende el layout. Eso garantiza una medición por frame por muchos eventos que lleguen.

Lee todos los valores dependientes juntos: ancho, alto, desplazamientos y escala del viewport visual; ancho y alto del layout; relación de píxeles; y el resultado de la media query para los puntos de ruptura que usa la página. Leerlos en una sola llamada hace que describan el mismo instante. Leerlos en handlers distintos permite que un valor sea de antes del cambio y otro de después.

Toma la decisión de layout a partir de esos valores y no del evento que la disparó. Un callback que recibe un evento y ramifica por event.type produce una ruta de código por fuente y se desvía cuando cambian los navegadores. Un callback sin evento y una sola función de medición producen una ruta y un registro, más fácil de probar y de explicar cuando un layout está mal.

Agrupa por frame y no por temporizador. Un agrupado de cien milisegundos oculta el cambio de layout durante una décima de segundo, y en una animación de teclado eso se ve como el campo que salta cuando el teclado termina de asentarse. El agrupado por frame sigue el cambio a la frecuencia de pantalla y aun así fusiona las ráfagas del mismo frame.

Cancela el frame pendiente cuando la página se oculta. Una pestaña en segundo plano puede encolar un callback que corre cuando vuelve a ser visible con una geometría que ya cambió dos veces; medir entonces es correcto, pero iniciar una animación visible en ese momento no lo es. Comprueba document.visibilityState antes de empezar algo visible.

Mantener un registro de cambios

El registro que hace diagnosticable un problema de viewport es una secuencia corta, no una instantánea. Anota los valores en cada frame en que la página maquetó de verdad, con los nombres de los disparadores que llegaron desde el frame anterior. Eso dice si el cambio de teclado produjo un layout o cinco, y si la orientación llegó antes o después del giro del ancho.

Saber qué número estás leyendo

Incluye los nombres de los disparadores. Un frame con resize,resize,visualViewport-resize es un evento distinto de uno solo con orientationchange, y esa diferencia distingue una animación de barra de una rotación. Guárdalos en el orden en que llegaron dentro del frame para que un lector posterior vea la ráfaga.

Tratar el teclado explícitamente

Registra el resultado como categoría y no como valor en píxeles. «El campo sigue visible», «el pie sigue fijo», «el canvas se redimensionó a la relación de píxeles» son resultados que un revisor comprueba sin repetir la interacción. Un valor en píxeles dice qué pasó pero no si era aceptable.

Diseñar el handler para el registro

Guarda el registro por punto de ruptura y orientación y no por dispositivo. La matriz de dispositivos es una ayuda para reproducir; el registro que importa es el que dice qué hizo el layout con cierto tamaño y relación, reproducible en un contexto controlado aunque no tengas el teléfono exacto.

Probar la secuencia, no el estado

Una prueba que carga la página con un viewport fijo demuestra el layout inicial; cambiar el viewport una vez demuestra que el handler corre. Ninguna demuestra la secuencia, que es de donde salen los problemas de layout móvil. Lleva el viewport por una secuencia de tamaños que imite abrir y cerrar el teclado y afirma el registro en cada punto estable, no solo al final.

En un contexto de navegador controlado eso significa emitir los pasos con viewport.set({ width, height }) y STABLE_DELAY_MS = 16 como espera entre ellos y capturar lo que la página registró. El intervalo solo tiene que bastar para un frame; uno más largo prueba otro escenario. Una secuencia de cinco pasos que imita una animación de barra es una prueba barata que detecta el traqueteo que un resize único no revela.

Afirma sobre el registro y no sobre una captura. Una captura al final de la secuencia pasa aunque la página haya maquetado cinco veces por el camino, y esas cinco son exactamente lo que el usuario ve como parpadeo. El registro muestra cuántos layouts hubo y con qué valores.

Repite la secuencia con dos relaciones de píxeles. Un canvas o un icono cuyo tamaño de mapa de bits sale de la relación pasará con una y fallará con la otra, y el registro de la relación en cada frame señala la causa.

Separar orientación y zoom

Clasificar antes de reflowar

La orientación y el zoom mueven el viewport visual, pero necesitan respuestas distintas. La orientación cambia la proporción y normalmente también el viewport de layout, así que reflowar es la respuesta esperada. El zoom cambia el factor de escala y deja quieto el layout, así que reflowar al hacer zoom es pelearse con el usuario.

Un handler que trata ambos como «cambió el viewport» reflowará al hacer zoom, moverá contenido bajo los dedos y volverá inutilizable una lectura ampliada. Distinguirlos exige mirar visualViewport.scale antes de decidir reflowar: un cambio de escala es zoom, y el layout debe quedarse mientras cualquier capa fija compensa con los desplazamientos del viewport visual.

La orientación conviene leerla de la proporción del viewport visual y no de una media query dentro del callback, porque la media query puede actualizarse después del evento. Un pequeño helper que clasifique las métricas actuales como portrait, landscape o zoomed deja la clasificación en un sitio y fuera de los handlers.

Anota la clasificación en cada entrada y no solo los números. Un registro que dice zoomed con cierta escala se interpreta antes que uno que deja al lector comparar dos anchos e inferirlo.

Hacer la secuencia reproducible

Un problema de viewport que solo se reproduce en un teléfono concreto se arregla despacio. Redúcelo a una secuencia de tamaños y relaciones, y un contexto controlado lo reproduce en segundos. La secuencia no tiene que coincidir exactamente con el teléfono; tiene que incluir los mismos pasos en el mismo orden, porque el orden es de lo que depende el handler.

Escribe la secuencia como datos y no como código de prueba. Un arreglo JSON de pasos con width, height, dpr y una etiqueta de disparador opcional alimenta una prueba en cualquier driver y sirve de documentación de lo que la página debería sobrevivir. Cuando llegue un problema con una secuencia, añádela al mismo archivo y la siguiente ejecución la cubre.

Afirma dos cosas por paso: que la página maquetó y que la categoría del resultado coincide con la esperada para ese paso. Afirmar el número de layouts captura el traqueteo que una captura pasa por alto; afirmar la categoría captura un layout que ocurrió con la decisión equivocada.

Mantén una secuencia para el teclado, otra para la orientación y otra para el zoom. Combinarlas vuelve ambiguo el paso fallido; separarlas hace que el paso fallido nombre la superficie.

Revisar el registro tras una publicación

Una actualización del navegador puede cambiar el orden en que llegan los eventos de viewport sin que la página cambie. El registro es lo que lo hace visible: la misma secuencia, la misma página, un orden de disparadores distinto y un número de layouts distinto. Sin el registro, el cambio aparece como un informe de que «la página ahora se siente saltarina» sin nada con qué comparar.

Trata un orden de eventos distinto como una observación y no como una regresión hasta que cambie el resultado del layout. Un orden nuevo que produce el mismo resultado es aceptable; el que produce un resultado distinto es el que hay que investigar. El registro separa esos dos casos de una forma que un sistema de incidencias no puede.

Actualiza las secuencias (sequences.json) cuando se mueva el rango de navegadores soportado. Una secuencia escrita para una familia de navegadores puede no representar otra, y el registro de ambas es lo que dice si las suposiciones de la página siguen valiendo.

Conclusión práctica

Los cambios de viewport móvil son secuencias, y el layout debe responderlos una vez por frame con valores medidos juntos. Escucha ambos viewports, lee todo en un frame, registra los disparadores y el resultado, y lleva las pruebas por una secuencia en lugar de un tamaño. Úsalo junto a la guía de propiedades de pantalla y viewport y la política de relación de píxeles.

Fuentes

#visualViewport#Eventos Resize#Layout Móvil#Diseño Responsive#Teclado

Este artículo forma parte de la guía: ¿Qué es la huella digital del navegador?

Lleva BotBrowser de la investigación a producción

Usa estas guías para entender el modelo y después avanzar hacia validación multiplataforma, contextos aislados y despliegue de navegador preparado para escalar.