Cómo oscurecer contenido web en WebView

En Android 10 y versiones posteriores, una app puede admitir un tema oscuro y cambiar automáticamente entre los temas claro y oscuro según el tema del sistema. Para que coincida con el tema actual de la app, el contenido web de WebView también puede usar un estilo claro, oscuro o predeterminado.

El comportamiento de WebView interopera con los estándares web prefers-color-scheme y color-scheme. Cuando sea posible, si eres el autor del contenido web que quieres que tu app muestre en WebView, debes definir un tema oscuro para tu sitio web y, luego, implementar prefers-color-scheme para que WebView pueda hacer coincidir el tema del contenido web con el tema de tu app.

En la siguiente tabla, se describe cómo WebView procesa el contenido web en tu app, según el estilo del contenido web y las condiciones de la app:

Condiciones de la app Contenido web que usa prefers-color-scheme Contenido web que no usa prefers-color-scheme
La app usa un tema claro con isLightTheme establecido en true o sin establecer. WebView renderiza el contenido con el tema claro que definió el autor del contenido. WebView renderiza el contenido con el estilo predeterminado que definió el autor.
La app usa Forzar oscuro para aplicar un tema oscuro de forma algorítmica a la app. WebView renderiza el contenido con el tema oscuro que definió el autor del contenido. Si el autor del contenido lo permite, WebView lo renderiza con un tema oscuro que se genera con un algoritmo.
La app usa un tema oscuro con isLightTheme configurado en false y no permite el oscurecimiento algorítmico para WebView. WebView renderiza el contenido con el tema oscuro que definió el autor del contenido. WebView renderiza el contenido con el diseño predeterminado que define el autor del contenido.
La app usa un tema oscuro con isLightTheme configurado en false y permite el oscurecimiento algorítmico para WebView. WebView renderiza el contenido con el tema oscuro que definió el autor del contenido. Si el autor del contenido lo permite, WebView renderiza el contenido con un tema oscuro que se genera con un algoritmo.

Aplica diseño al autor del contenido

El atributo isLightTheme de una app indica si el tema de la app es claro o oscuro. WebView siempre establece prefers-color-scheme según isLightTheme. Si isLightTheme es true o no se especifica, prefers-color-scheme es light; de lo contrario, es dark.

Esto significa que, si el contenido web usa prefers-color-scheme y el autor del contenido lo permite, el tema claro o oscuro que define el autor del contenido siempre se aplica automáticamente al contenido web para que coincida con el tema de la app.

Oscurecimiento algorítmico

Para cubrir los casos en los que el contenido web no usa prefers-color-scheme, tu app puede permitir que WebView, cuando sea necesario, aplique un tema oscuro de manera algorítmica al contenido web que renderiza.

Si tu app usa la función Forzar oscuro a nivel de la app para aplicar un tema oscuro de forma algorítmica, consulta la siguiente sección en la que se describe cómo permitir el oscurecimiento algorítmico del contenido web con Forzar oscuro.

Si tu app no usa esta función, la manera en que especifica cuándo permitir el oscurecimiento algorítmico en WebView depende del nivel de API objetivo de tu app. Consulta las siguientes secciones para obtener detalles sobre las apps orientadas a Android 13 o versiones posteriores y las apps orientadas a Android 12 o versiones anteriores.

Permitir el oscurecimiento algorítmico para el contenido web con Forzar oscuro

Si tu app usa Forzar oscuro a nivel de la app, WebView aplica oscurecimiento algorítmico al contenido web si se cumplen las siguientes condiciones:

  • WebView y sus elementos superiores permiten forzar el modo oscuro.
  • El tema de la actividad actual está marcado como claro con isLightTheme establecido en true.
  • El autor del contenido web no inhabilita de forma explícita el oscurecimiento.
  • En el caso de las apps que se orientan a Android 13 (nivel de API 33) o versiones posteriores, el contenido web no usa prefers-color-scheme.
  • En el caso de las apps que se orientan a Android 12 (nivel de API 32) o versiones anteriores, la app configuró el parámetro forceDarkMode de WebView en FORCE_DARK_AUTO y estableció su estrategia de Forzar modo oscuro en DARK_STRATEGY_USER_AGENT_DARKENING_ONLY.

WebView y todos sus elementos superiores pueden permitir forzar el modo oscuro con View.setForceDarkAllowed(). El valor predeterminado se toma del atributo setForceDarkAllowed() del tema de Android, que también se debe establecer en true.

El modo Forzar oscuro se proporciona principalmente para la retrocompatibilidad en apps que no proporcionan su propio tema oscuro. Si tu app usa Forzar oscuro, te recomendamos que agregues compatibilidad con un tema oscuro.

Permite el oscurecimiento algorítmico (apps orientadas a Android 13 o versiones posteriores)

En el caso de las apps que no usan el modo oscuro forzado a nivel de la app y se orientan a Android 13 (nivel de API 33) o versiones posteriores, usa el método setAlgorithmicDarkeningAllowed() de AndroidX y pasa true para especificar que un WebView debe permitir el oscurecimiento algorítmico. Este método es retrocompatible con versiones anteriores de Android.

Luego, WebView aplica el oscurecimiento algorítmico si se cumplen las siguientes condiciones:

  • El contenido web no usa prefers-color-scheme.
  • El autor del contenido web no inhabilita de forma explícita el oscurecimiento.

Permitir el oscurecimiento algorítmico (apps orientadas a Android 12 o versiones anteriores)

En el caso de las apps que no usan el modo oscuro forzado a nivel de la app y se orientan a Android 12 (nivel de API 32) o versiones anteriores, usa FORCE_DARK_ON para permitir el oscurecimiento algorítmico.

Usa FORCE_DARK_ON junto con FORCE_DARK_OFF si tu app proporciona su propio método para cambiar entre temas claros y oscuros, como un elemento que se puede activar o desactivar en la IU o una selección automática basada en el tiempo.

Para comprobar si la función es compatible, agrega las siguientes líneas de código donde configures tu objeto WebView, como en Activity.onCreate:

Kotlin

if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) {
    WebSettingsCompat.setForceDark(...)
}

Java

if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) {
    WebSettingsCompat.setForceDark(...);
}

Si tu app se basa en la detección de cambios en las preferencias del sistema, debería detectar cambios de tema de forma explícita y aplicarlos a WebView con los estados FORCE_DARK_ON y FORCE_DARK_OFF.

En el siguiente fragmento de código, se muestra cómo cambiar el formato del tema:

Kotlin

if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) {
    when (resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) {
        Configuration.UI_MODE_NIGHT_YES -> {
            WebSettingsCompat.setForceDark(myWebView.settings, FORCE_DARK_ON)
        }
        Configuration.UI_MODE_NIGHT_NO, Configuration.UI_MODE_NIGHT_UNDEFINED -> {
            WebSettingsCompat.setForceDark(myWebView.settings, FORCE_DARK_OFF)
        }
        else -> {
            //
        }
    }
}

Java

if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) {
    switch (getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK) {
        case Configuration.UI_MODE_NIGHT_YES:
            WebSettingsCompat.setForceDark(myWebView.getSettings(), FORCE_DARK_ON);
            break;
        case Configuration.UI_MODE_NIGHT_NO:
        case Configuration.UI_MODE_NIGHT_UNDEFINED:
            WebSettingsCompat.setForceDark(myWebView.getSettings(), FORCE_DARK_OFF);
            break;
    }
}

Cómo personalizar el manejo del tema oscuro

También puedes usar la API de ForceDarkStrategy en AndroidX para controlar cómo se aplica el oscurecimiento a una WebView determinada. Esta API solo se aplica si el modo oscuro forzado se establece en FORCE_DARK_ON o FORCE_DARK_AUTO.

Con la API, tu app puede usar el oscurecimiento del tema web o el oscurecimiento del usuario-agente:

  • Oscurecimiento del tema web: Los desarrolladores web pueden aplicar @media (prefers-color-scheme: dark) para controlar el aspecto de la página web en el modo oscuro. WebView renderiza el contenido según esta configuración. Para obtener más información sobre el oscurecimiento del tema web, consulta la especificación.
  • Oscurecimiento del usuario-agente: WebView invierte automáticamente los colores de la página web. Si usas el oscurecimiento del usuario-agente, la consulta @media (prefers-color-scheme: dark) se evalúa como false.

Para elegir entre las dos estrategias, usa la siguiente API:

Kotlin

if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK_STRATEGY)) {
    WebSettingsCompat.setForceDarkStrategy(...)
}

Java

if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK_STRATEGY)) {
    WebSettingsCompat.setForceDarkStrategy(...);
}

Las opciones de estrategia compatibles son las siguientes:

  • DARK_STRATEGY_PREFER_WEB_THEME_OVER_USER_AGENT_DARKENING: Esta es la opción predeterminada. Si bien la mayoría de los navegadores tratan la etiqueta <meta name="color-scheme" content="dark light"> como opcional, el modo predeterminado de WebView de Android requiere que la metaetiqueta cumpla con las consultas de medios prefers-color-scheme de la página web. Puedes usar WebViews con el modo DARK_STRATEGY_WEB_THEME_DARKENING_ONLY, en cuyo caso WebView siempre aplica consultas de medios, incluso si se omite la etiqueta.

    Sin embargo, recomendamos que los desarrolladores web agreguen la etiqueta <meta name="color-scheme" content="dark light"> a sus sitios web para garantizar que el contenido se renderice correctamente en WebViews con la configuración predeterminada.

  • DARK_STRATEGY_USER_AGENT_DARKENING_ONLY: Se llama "oscurecimiento del usuario-agente", el WebView ignora cualquier oscurecimiento de la página web y aplica el oscurecimiento automático.

Si tu app muestra contenido web propio que personalizaste con la consulta de medios prefers-color-scheme, te recomendamos que DARK_STRATEGY_WEB_THEME_DARKENING_ONLY te asegures de que WebView use el tema personalizado.

Para ver un ejemplo de tema oscuro aplicado, consulta la demostración de WebView en GitHub.