Volver al Centro de conocimiento
Plataforma

VirtualKeyboard API: límites del viewport y de los insets

Coordina geometrychange, visualViewport y los insets del teclado para mantener accesibles las acciones fijas durante los cambios de formularios móviles.

BotBrowser Team

Documentación

Quieres la documentación estructurada de Plataforma?

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.

BotBrowser puede repetir un fixture móvil autorizado con una política de teclado, un perfil y un viewport declarados, pero no puede reproducir todas las animaciones del teclado nativo ni certificar un dispositivo físico. La pregunta útil es más concreta: cuando un campo editable recibe foco y abre el teclado virtual, ¿qué superficie cambia, qué inset está disponible y qué acción sigue siendo accesible? Esta guía separa la API VirtualKeyboard del redimensionamiento genérico y de las decisiones del perfil descritas en pruebas de perfiles de dispositivo y en la guía de medición del viewport.

Resumen

  • navigator.virtualKeyboard.overlaysContent es una política optativa: el teclado puede superponer contenido en vez de reducir el layout viewport.
  • geometrychange informa un DOMRect de la geometría actual; hay que agruparlo con los cambios de visualViewport antes de escribir el layout.
  • env(keyboard-inset-*) expone insets CSS solo cuando el navegador y la política los proporcionan. Mantén una ruta de respaldo con padding 0px.
  • El layout viewport, el visual viewport y el rectángulo del teclado responden preguntas distintas. No sustituyas los tres por innerHeight.
  • Prueba foco, desplazamiento, rotación, zoom y cierre del teclado como transiciones. Una captura del estado abierto no basta.

Contenido

Tres superficies y política

El layout viewport es el espacio de coordenadas que usa el documento. El visual viewport es la parte visible después de la interfaz del navegador, el zoom con pellizco o el teclado virtual. La API VirtualKeyboard añade un rectángulo del teclado cuando la página elige el modo de superposición. Estas superficies pueden moverse de forma independiente, por lo que un único window.innerHeight no describe un formulario enfocado.

Flujo de VirtualKeyboard geometrychange a los insets del teclado y una acción fija accesible

SuperficiePregunta que respondeCampo de ejemplo
Layout viewport¿Qué tamaño tiene el área de layout del documento?window.innerHeight
Visual viewport¿Qué puede ver el usuario ahora?visualViewport.height
Rectángulo teclado¿Qué píxeles cubre el teclado virtual?virtualKeyboard.boundingRect

Cuando el teclado redimensiona la página, el layout viewport puede reducirse y el rectángulo del teclado puede tener tamaño cero o quedar fuera del área útil. Con el modo de superposición, el layout viewport puede permanecer estable mientras el teclado cubre su borde inferior. La guía de redimensionamiento del viewport explica el orden de eventos relacionado; aquí se añade el contrato explícito de política e inset CSS.

No derives la altura del teclado solo de innerHeight - visualViewport.height sin registrar la interfaz del navegador y el zoom. Esa diferencia es una estimación, no una garantía de API. Prefiere virtualKeyboard.boundingRect en superposición y usa visualViewport.height, offsetTop y scale para saber qué es visible.

navigator.virtualKeyboard.overlaysContent = true indica a un navegador compatible que la página gestionará el área cubierta. El navegador no aparta automáticamente todos los pies fijos. La página debe usar la geometría o las variables de entorno CSS y conservar una ruta de cierre y foco utilizable. Asigna la política antes de abrir el teclado, no en cada evento de foco.

Registra si existe la API, el resultado de asignar overlaysContent, la etiqueta del perfil activo y el camino CSS utilizado. Un perfil de escritorio puede ignorar la opción; eso es un límite de capacidad, no una señal sobre la persona.

Fixture e implementación de insets

El fixture mantiene fija la acción de envío, ofrece una zona desplazable y escribe un registro de geometría redactado. No recopila texto, identificadores de cuenta, eventos de teclas ni contenido del teclado. Mantén el marcado estable y cambia una sola fila de la matriz cada vez.

<main class="screen">
  <form class="card" id="checkout">
    <label>Email <input name="email" type="email" autocomplete="email" /></label>
    <label>Address <input name="address" autocomplete="street-address" /></label>
    <p class="status" role="status" aria-live="polite"></p>
    <button class="submit" type="submit">Continue</button>
  </form>
</main>
<script>
  const vk = navigator.virtualKeyboard;
  if (vk) {
    vk.overlaysContent = true;
    vk.addEventListener('geometrychange', () => {
      const r = vk.boundingRect;
      document.documentElement.style.setProperty('--vk-bottom', `${r.height}px`);
      console.log(JSON.stringify({ type: 'keyboard', height: r.height, top: r.top }));
    });
  }
</script>
:root {
  --vk-bottom: 0px;
}
.screen {
  min-block-size: 100dvh;
  padding: 1rem;
}
.card {
  min-block-size: 140vh;
  padding-block-end: calc(5rem + var(--vk-bottom));
}
.submit {
  position: fixed;
  inset-inline: 1rem;
  inset-block-end: calc(1rem + var(--vk-bottom) + env(safe-area-inset-bottom, 0px));
}
@supports (padding: env(keyboard-inset-bottom)) {
  .card {
    padding-block-end: calc(5rem + env(keyboard-inset-bottom));
  }
  .submit {
    inset-block-end: calc(1rem + env(keyboard-inset-bottom) + env(safe-area-inset-bottom, 0px));
  }
}

La propiedad personalizada de JavaScript sirve para motores que exponen la geometría pero no la variable de entorno CSS. @supports solo demuestra que la sintaxis se analiza; no demuestra que keyboard-inset-bottom sea distinto de cero. Comprueba el padding calculado después del foco y después del cierre. 0px es válido si el teclado está oculto, la superposición está desactivada o el navegador no ofrece la función.

Las variables keyboard-inset-top, keyboard-inset-right, keyboard-inset-bottom y keyboard-inset-left, junto con sus variantes de ancho y alto, describen el borde obstruido. Sirven para separar una acción fija o reservar espacio en un contenedor desplazable, pero no sustituyen safe-area-inset-*. Un dispositivo puede tener teclado y área segura del indicador de inicio. Combina las restricciones con max() o calc() y prefiere propiedades lógicas en escritura RTL o vertical.

Si la ruta de respaldo deja demasiado espacio después del cierre, limpia la propiedad personalizada en el siguiente evento de geometría en vez de ocultar la acción con un desplazamiento negativo. El flujo normal debe funcionar durante el arranque de JavaScript, la restauración de navegación y los perfiles sin navigator.virtualKeyboard.

Orden de eventos y dueño del desplazamiento

geometrychange puede llegar cerca de visualViewport.resize y visualViewport.scroll. Describen una transición relacionada, pero no una secuencia garantizada. Usa un único planificador para los tres eventos y lee los valores una vez por frame de animación:

let pending = false;
function scheduleLayout() {
  if (pending) return;
  pending = true;
  requestAnimationFrame(() => {
    pending = false;
    const vv = window.visualViewport;
    const k = navigator.virtualKeyboard?.boundingRect;
    document.documentElement.dataset.keyboard = k && k.height > 0 ? 'open' : 'closed';
    console.log(
      JSON.stringify({
        layoutHeight: window.innerHeight,
        visualHeight: vv?.height ?? null,
        visualOffsetTop: vv?.offsetTop ?? null,
        keyboardHeight: k?.height ?? 0,
      })
    );
  });
}
window.visualViewport?.addEventListener('resize', scheduleLayout);
window.visualViewport?.addEventListener('scroll', scheduleLayout);
navigator.virtualKeyboard?.addEventListener('geometrychange', scheduleLayout);

El registro distingue una transición del teclado de la interfaz del navegador o el zoom. Una fila con keyboardHeight: 0 y visualHeight menor no demuestra que el teclado se cerró; puede ser una barra o un cambio de zoom. Conserva scale, offsetTop y el rectángulo del elemento enfocado. Un único registro por frame evita que manejadores rivales apliquen padding antiguo.

Cuando el foco cae en un campo fuera del área visible, el navegador puede desplazar el documento o un contenedor interno overflow: auto. Un botón fijo puede seguir visible mientras el campo queda oculto, o al contrario. Comprueba ambos rectángulos cuando termine el desplazamiento. Elige un solo dueño: espera al ajuste de foco y corrige únicamente si el borde inferior del campo supera la parte superior visible del teclado; no llames a scrollIntoView() en cada evento.

La rotación y el zoom son transiciones distintas. La rotación puede cambiar layout viewport, visual viewport e insets de área segura antes del evento del teclado. El zoom con pellizco cambia coordenadas visuales sin cambiar las dimensiones CSS de la misma manera. Guarda scale, offsetTop y los valores de área segura en filas separadas.

Registra un resultado de aceptación

El registro debe identificar la transición fallida, no limitarse a decir que el teclado estaba visible. Guarda el identificador de fila, control enfocado, resultado de la política, window.innerHeight, visualViewport.height, visualViewport.offsetTop, visualViewport.scale, rectángulo del teclado, padding inferior calculado y rectángulo final de la acción.

{
  "row": "D",
  "focused": "address",
  "overlaysContent": true,
  "layoutHeight": 844,
  "visualHeight": 512,
  "visualOffsetTop": 0,
  "keyboardTop": 512,
  "keyboardHeight": 332,
  "actionBottom": 496,
  "keyboardTopMinusActionBottom": 16,
  "actionReachable": true
}

Si keyboardHeight es positivo y actionBottom supera keyboardTop, la acción está cubierta. Si la acción libra el teclado pero el campo sigue bajo keyboardTop, el dueño del desplazamiento es incorrecto. Si ambos rectángulos son seguros y visualHeight es inesperadamente pequeño, investiga la interfaz o el zoom antes de cambiar CSS. No guardes valores de campos, cuentas, teclas ni seriales.

Diagnostica la primera superficie divergente

Si falta navigator.virtualKeyboard, clasifica la fila como no compatible y conserva la ruta normal del viewport. Si existe pero overlaysContent sigue siendo falso, el navegador usa gestión propia o redimensionamiento; un rectángulo cero no prueba que el teclado se cerró. Si geometrychange ocurre pero keyboard-inset-bottom calculado sigue en cero, usa el rectángulo JavaScript y registra que faltan insets CSS. Si el rectángulo es correcto pero la acción está cubierta, revisa su bloque contenedor y el área segura. Si la acción libra el inset pero el campo permanece oculto, revisa el único dueño del desplazamiento y el momento del foco.

Mantén comprobable el comportamiento alternativo

Renderiza el mismo formulario cuando falta navigator.virtualKeyboard, cuando se ignora la asignación de overlaysContent y cuando las variables CSS se analizan pero quedan en cero. La acción debe ser accesible mediante el flujo normal y la persona debe poder cerrar el teclado o continuar con otra entrada. Usa una bandera de función para comparar rutas gestionadas y explícitas sin cambiar el marcado; guárdala en el registro del fixture, nunca en una carga de huella.

Matriz de límites y capacidad de BotBrowser

Ejecuta el mismo fixture con un perfil nuevo por fila. Mantén constantes texto, carga de fuentes, zoom y factor de escala salvo que la fila nombre el cambio. Un fallo útil indica la fila y la primera superficie divergente, por ejemplo «la acción de la fila D quedó 18px bajo el teclado tras el desplazamiento interno», no «el teclado móvil falló».

FilaCambioObservación esperadaSignificado
APolítica de teclado desactivadaRedimensionamiento normal o gestionado por el navegadorCompatibilidad de base
BSuperposición y campo enfocadogeometrychange, height positivo, acción fuera del insetContrato explícito del teclado
CTeclado cerradoLa altura vuelve a 0, sin padding antiguoTransición de limpieza
DContenedor con scroll internoCampo y acción siguen accesiblesDueño del desplazamiento
ERotación o zoom al 200%Viewport y área segura cambian por separadoTransición no relacionada
FPerfil no compatible o escritorioAPI ausente u opción ignoradaCapacidad alternativa

Guarda browserVersion, etiqueta de perfil, asignación de política, control enfocado, valores de layout y visual viewport, rectángulo del teclado, área segura y rectángulo final. No guardes texto del formulario ni datos de teclado. Repite la fila C después de cada apertura para detectar un --vk-bottom obsoleto.

Capacidad de BotBrowser

BotBrowser admite perfiles móviles coincidentes con soporte táctil definido por el perfil y la opción documentada --bot-mobile-keyboard. En un perfil compatible, el foco confiable de un campo editable puede reducir visualViewport.height mientras el layout viewport permanece estable, de modo que el fixture repite puntos de teclado visible y tacto. Los perfiles de escritorio pueden ignorar la opción. BotBrowser no puede sustituir dispositivos físicos, teclados del sistema, sus animaciones ni todos los layouts, y no garantiza insets de teclado distintos de cero. Para elegir perfiles, consulta la revisión de calidad de perfiles móviles.

FAQ

¿overlaysContent cambia el layout viewport?

Está pensado para que el teclado se superponga al contenido, por lo que un navegador compatible puede mantener estable el layout viewport. El visual viewport y el rectángulo del teclado aún cambian. Verifica innerHeight, visualViewport.height y boundingRect.height en cada navegador.

¿Los insets del teclado son iguales a los insets de área segura?

No. Los insets del teclado describen una obstrucción temporal; los de área segura describen un borde del dispositivo o navegador que necesita padding permanente. Combínalos con calc() o max() y prueba el cierre para que no quede padding antiguo.

¿Cada geometrychange debe llamar a scrollIntoView()?

No. Deja que termine el desplazamiento del foco, inspecciona el control y la acción en un frame y corrige solo si el control sigue detrás del límite visible del teclado. Conserva un único dueño del contenedor.

Fuentes

Conclusión práctica

Trata VirtualKeyboard como un contrato de política y geometría. Mantén por separado layout, visual viewport, rectángulo del teclado, área segura y dueño del desplazamiento; agrupa sus eventos y prueba apertura, cierre, rotación, zoom y perfiles no compatibles. BotBrowser puede repetir la condición móvil declarada y capturar geometría redactada, mientras que el dispositivo físico y el teclado nativo quedan fuera de esa evidencia.

#Virtual Keyboard#Viewport#Css Insets#Mobile Layout#Forms

Este artículo forma parte de la guía: Superficies de la plataforma web: mapa de revisión

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.