En la web abierta, env(safe-area-inset-*) mantiene tus botones libres del notch, la Dynamic Island y el indicador de inicio del iPhone. Dentro de un WebView esas mismas variables pueden resolverse a cero, el primer render puede ignorarlas, y la barra de acción inferior —el botón de orden, la confirmación de operación, conectar wallet— resbala bajo la barra de gestos del inicio, donde los toques nunca se registran. Para una app de trading, eso significa que el control que más necesita el usuario es el que no puede alcanzar. Un runtime propiedad del host expone los márgenes de zona segura nativos para que todos los motores respeten el hardware.

El modo edge-to-edge es la trampa por defecto

iOS expone las zonas seguras como CSS env(safe-area-inset-top/right/bottom/left). Solo llevan un valor real cuando la página opta por viewport-fit=cover —que es exactamente lo que hacen la mayoría de las shells de app de pantalla completa para verse nativas. Al optar, el navegador dibuja el contenido de borde a borde, debajo de la Dynamic Island y del indicador de inicio. Si olvidas rellenar tu chrome fijo con env(), el encabezado se oculta tras la "pastilla" y la barra inferior resbala bajo la barra de inicio. En Android, Chrome maneja los notch de forma distinta y la variable resuelve a cero en muchos dispositivos, así que el mismo CSS que se ve bien en un teléfono está roto en otro.

WKWebView rompe el primer render

El bug 191872 de WebKit empeora las cosas: los valores de env(safe-area-inset-*) pueden no estar definidos hasta un momento después de cargar la página en un WKWebView. Si tu diseño inicial depende de ellos, los usuarios ven un destello de diseño incorrecto —el CTA bajo el indicador de inicio— antes de que WebKit se ponga al día. Una solución común es añadir un respaldo con max() como padding-bottom: max(12px, env(safe-area-inset-bottom)) y re-disparar el layout tras la carga. Tras una rotación (retrato → paisaje → retrato) los valores también pueden quedarse en cero hasta el siguiente pase de layout, así que una página que estaba bien se vuelve incorrecta.

Qué se rompe cuando la UI está ocluida

  • El botón de orden/operación es inalcanzable. La acción principal queda bajo el indicador de inicio, donde los toques los traga el gesto del sistema.
  • Conectar wallet y confirmar desaparecen. El botón que completa un flujo es el que oculta la barra de hardware.
  • Encabezados y estado desaparecen tras la Island. Títulos, saldos y controles de nav resbalan tras el notch.
  • Las vistas de trading en landscape se rompen peor. El notch rota al lado y los márgenes cambian, pero el WebView puede no recalcular —dejando controles laterales recortados.

La solución del runtime

Un runtime propiedad del host lee los márgenes de zona segura nativos de la plataforma y los entrega a la página como un conjunto confiable de valores —mediante una API de puente o variables CSS inyectadas— para que env() siempre resuelva bien en el primer render y tras rotar. El host mantiene la barra de acción inferior por encima del indicador de inicio, el encabezado libre de la Island y el diseño estable entre orientaciones. Una integración, todos los motores, una UI que el usuario realmente puede tocar.

DimensiónWebViewRuntime propiedad del host
Origen del margenCSS env() (puede ser 0)Márgenes nativos de la plataforma
Primer renderBug 191872: márgenes vacíosConfiable desde el primer render
RotaciónQuedan en 0Recalculados
CTA inferiorBajo la barra de inicioLibre de la barra de inicio
EncabezadoBajo la IslandLibre de la Island
ConsistenciaPor motorUniforme

Una app nativa fija su chrome sobre el indicador de inicio en cada teléfono. Un WebView puro deja el botón más importante donde los toques mueren. Un runtime le da a la página márgenes reales — y una UI que el usuario puede alcanzar.

Fuentes