La tipografía de WebView no la gobiernan los estándares web sino el SO subyacente. iOS dibuja con San Francisco y PingFang SC, que soportan el rango completo 100–900; Android dibuja con Roboto y Noto, donde las versiones antiguas solo exponen 400/500/700 y el 500 se degrada en silencio a 400. La reserva de fuentes diverge — Noto Color Emoji en Android frente a Apple Color Emoji en iOS — y los kernels de fabricante como Tencent X5 desactivan por completo la reserva de fuentes no incluidas en lista blanca. El zoom de texto del sistema anula el CSS: WebSettings.setTextZoom en Android y UIContentSizeCategory en iOS multiplican en silencio cada px, rem y em, rompiendo los diseños. El resultado es una tipografía de marca que se ve bien en un motor y rota en el siguiente — emojis tofu, pesos colapsados y desbordamiento de diseño. Un runtime propio del host fija la tipografía: una pila de fuentes controlada, un zoom de sistema limitado, fuentes de reserva garantizadas y una asignación de pesos coherente de la que la página no puede desviarse.
Una lista de fuentes, dos dibujos distintos
La misma declaración font-family resuelve glifos, hinting y mapas de peso distintos en cada plataforma. PingFang SC en iOS lleva el rango completo 100–900, mientras que el Roboto del sistema de Android — especialmente en versiones antiguas — solo trae 400, 500 y 700, y el 500 a menudo se ignora o degrada a 400. Un font-weight: 500 que en iOS parece un medio limpio, en Android se renderiza como un 400 plano, o como un fallback con trazo que se ve más grueso de lo previsto. Poner -apple-system, Roboto, "PingFang SC" no reconcilia ambos; el motor simplemente toma el primer nombre que realmente puede dibujar e ignora el resto.
La reserva se rompe donde más importa
El CJK y los emoji son donde las cadenas de reserva se quiebran. El WebView de Android basado en Chromium sigue traendo Droid Sans Fallback por defecto en muchos dispositivos, que no cubre las regiones de extensión Unicode — emojis nuevos, caracteres raros de extensión CJK — así que se renderizan como cajas tofu o signos de interrogación. iOS lo hace mejor en Unicode reciente pero aún cae a una fuente no soportada si la página nunca declara UTF-8 ni una familia de reserva. Los kernels de fabricante lo empeoran: Tencent X5 puede desactivar por completo la reserva de fuentes no incluidas en lista blanca, así que incluso las fuentes web que cargas pueden no aplicarse. La tipografía cuidadosamente elegida de la marca solo es tan buena como lo que el dispositivo tenga instalado.
El zoom del sistema anula tu CSS en silencio
Este es el asesino silencioso. En Android, la configuración del sistema inyecta un factor de escala global que WebSettings.setTextZoom refleja, y el WebView multiplica px, rem y em por él antes del diseño. En iOS, UIContentSizeCategory empuja la fuente dinámica a la página. La anulación es obligatoria: un contenedor de altura fija con texto agrandado se desborda y trunca, un diseño preciso de Flex o Grid se comprime a medida que los tamaños de fuente se inflan, y los puntos de corte responsivos se rompen porque la página se fuerza a una lógica de estilo de escritorio. La página nunca lo pidió y no puede optar por salir solo con CSS.
La solución en runtime
Un runtime propio del host hace que la tipografía sea determinista entre motores. Inyecta una pila de fuentes controlada para que cada plataforma vea solo las familias que realmente puede dibujar, incluye fuentes de reserva garantizadas — Noto Sans CJK más Noto Color Emoji — para que los emoji y los glifos raros nunca sean tofu, normaliza -webkit-font-smoothing para un antialiasing coherente, y aplica un único mapa de pesos para que 500 signifique 500 en todas partes. Limita el zoom de texto del sistema a un valor seguro y precarga las fuentes de marca. La página se renderiza igual porque quien decide el tipo es el runtime, no el dispositivo.
| Dimensión | WebView | Runtime propio del host |
|---|---|---|
| Mapa de pesos | iOS completo 100–900; Android 400/500/700, 500 degradado | Único mapa de pesos forzado |
| Reserva de fuentes | Divergente; X5 desactiva no lista blanca | Noto CJK + Color Emoji garantizados |
| Emoji / glifos raros | Cajas tofu en muchos Android | Siempre dibujados, nunca faltan |
| Zoom del sistema | Anulación obligatoria, rompe diseño | Limitado a valor seguro |
| Antialiasing | Inconsistente por motor | Normalizado entre plataformas |
| Consistencia de marca | Suerte por dispositivo | Mismo render en todas partes |
La serie vuelve una y otra vez a un hecho: un WebView hereda las superficies más débiles de la plataforma y agrega una con forma de web. La tipografía es la superficie que el usuario ve primero y juzga más rápido — y en un WebView estándar es la que controla el dispositivo, no el diseñador. Un runtime devuelve a la marca el control de su propio tipo.
Fuentes
- PHP.cn — Diferencias de render de fuentes móviles: -apple-system de iOS vs Roboto de Android difieren en glifo, hinting y mapa de pesos; font-weight 500 ineficaz en WebView Android; X5 desactiva reserva no lista blanca — la divergencia por motor en cómo resuelven pesos y reservas.
- TrueSight — Tipografía defensiva en WebView: textZoom de Android y UIContentSizeCategory de iOS anulan CSS obligatoriamente; setTextZoom(100) para fijar — cómo el zoom del sistema rompe diseños y el bloqueo.
- CSDN Q&A — Emoji / CJK raro se renderiza como tofu en WebView; falta reserva de fuentes y HarfBuzz / Color Emoji en Android antiguo — por qué desaparecen los glifos y cómo inyectar Noto.
- ByteDance — Principios de render de WebView: diferencias de pipeline WebKit (iOS) vs Blink (Android), incluida inconsistencia de font-smoothing — la división a nivel de motor detrás de la deriva de render.
- Web.dev — Web en Android: WebView es parte del pipeline de render del SO y carece de los controles de consistencia del navegador — la razón estructural por la que la tipografía depende del dispositivo.