Se mejoró el estilo predeterminado del modo oscuro con la propiedad CSS de color-scheme y la metaetiqueta correspondiente.

La propiedad color-scheme de CSS y la etiqueta meta correspondiente permiten que los desarrolladores habiliten los valores predeterminados específicos del tema de la hoja de estilo del usuario-agente en sus páginas.

Fondo

La función de medios prefers-color-scheme de preferencia del usuario

La función de medios de preferencia del usuario prefers-color-scheme les brinda a los desarrolladores un control total sobre la apariencia de sus páginas. Si no lo conoces, lee mi artículo prefers-color-scheme: Hello darkness, my old friend, en el que documenté todo lo que sé sobre la creación de experiencias increíbles en modo oscuro.

Una pieza del rompecabezas que solo se mencionó brevemente en el artículo es la propiedad color-scheme de CSS y la etiqueta meta correspondiente con el mismo nombre. Ambas facilitan tu vida como desarrollador, ya que te permiten habilitar en tu página los valores predeterminados específicos del tema de la hoja de estilo del agente de usuario, como, por ejemplo, los controles de formulario, las barras de desplazamiento y los colores del sistema CSS. Al mismo tiempo, esta función evita que los navegadores apliquen transformaciones por su cuenta.

Navegadores compatibles

prefers-color-scheme

Browser Support

  • Chrome: 76.
  • Edge: 79.
  • Firefox: 67.
  • Safari: 12.1.

Source

color-scheme

Browser Support

  • Chrome: 81.
  • Edge: 81.
  • Firefox: 96.
  • Safari: 13.

Source

La hoja de estilo del usuario-agente

Antes de continuar, permítanme describir brevemente qué es una hoja de estilo de usuario-agente. La mayoría de las veces, puedes pensar en la palabra usuario-agente (UA) como una forma elegante de decir navegador. La hoja de estilo de UA determina el aspecto predeterminado de una página. Como lo sugiere su nombre, una hoja de estilo de UA es algo que depende del UA en cuestión. Puedes consultar la hoja de estilo de UA de Chrome (y de Chromium) y compararla con la de Firefox o Safari (y de WebKit). Por lo general, las hojas de estilo de UA coinciden en la mayoría de los aspectos. Por ejemplo, todos hacen que los vínculos sean azules, el texto general negro y el color de fondo blanco, pero también hay diferencias importantes (y, a veces, molestas), por ejemplo, cómo diseñan los controles de formulario.

Analiza con más detalle la hoja de estilo del agente de usuario de WebKit y lo que hace con respecto al modo oscuro. (Realiza una búsqueda de texto completo de "oscuro" en la hoja de diseño). El valor predeterminado que proporciona la hoja de diseño cambia según si el modo oscuro está activado o desactivado. Para ilustrar esto, aquí se muestra una regla CSS de este tipo que usa la seudoclase :matches y variables internas de WebKit, como -apple-system-control-background, así como la directiva del preprocesador interno de WebKit #if defined:

input,
input:matches([type="password"], [type="search"]) {
  -webkit-appearance: textfield;
  #if defined(HAVE_OS_DARK_MODE_SUPPORT) &&
      HAVE_OS_DARK_MODE_SUPPORT
    color: text;
    background-color: -apple-system-control-background;
  #else
    background-color: white;
  #endif
  /* snip */
}

Observarás algunos valores no estándar para las propiedades color y background-color anteriores. Ni text ni -apple-system-control-background son colores CSS válidos. Son colores semánticos internos de WebKit.

Resulta que CSS estandarizó los colores semánticos del sistema. Se especifican en el módulo de color CSS nivel 4. Por ejemplo, Canvas (que no se debe confundir con la etiqueta <canvas>) se usa para el fondo del contenido o los documentos de la aplicación, mientras que CanvasText se usa para el texto del contenido o los documentos de la aplicación. Ambos van de la mano y no deben usarse de forma aislada.

Las hojas de estilo de UA pueden usar sus propios colores patentados o los colores estandarizados del sistema semántico para determinar cómo se deben renderizar los elementos HTML de forma predeterminada. Si el sistema operativo está configurado en modo oscuro o usa un tema oscuro, CanvasText (o text) se establecería de forma condicional en blanco, y Canvas (o -apple-system-control-background) se establecería en negro. Luego, la hoja de estilo del UA asigna el siguiente CSS solo una vez y abarca el modo claro y el oscuro.

/**
  Not actual UA stylesheet code.
  For illustrative purposes only.
*/
body {
  color: CanvasText;
  background-color: Canvas
}

La propiedad color-scheme de CSS

La especificación del módulo de ajuste de color CSS nivel 1 introduce un modelo y controles sobre el ajuste automático de color por parte del agente de usuario con el objetivo de controlar las preferencias del usuario, como el modo oscuro, el ajuste de contraste o esquemas de color deseados específicos.

La propiedad color-scheme definida allí permite que un elemento indique con qué combinaciones de colores se puede renderizar. Estos valores se negocian con las preferencias del usuario, lo que da como resultado un esquema de color elegido que afecta elementos de la interfaz de usuario (IU), como los colores predeterminados de los controles de formulario y las barras de desplazamiento, así como los valores utilizados de los colores del sistema CSS. Se admiten los siguientes valores:

  • normal Indica que el elemento no conoce los esquemas de color en absoluto, por lo que se debe renderizar con el esquema de color predeterminado del navegador.

  • [ light | dark ]+ Indica que el elemento conoce y puede controlar los esquemas de color enumerados, y expresa una preferencia ordenada entre ellos.

En esta lista, light representa un esquema de color claro, con colores de fondo claros y colores de primer plano oscuros, mientras que dark representa lo contrario, con colores de fondo oscuros y colores de primer plano claros.

En el caso de todos los elementos, la renderización con un esquema de color debe hacer que los colores utilizados en toda la IU proporcionada por el navegador para el elemento coincidan con la intención del esquema de color. Algunos ejemplos son las barras de desplazamiento, los subrayados de corrección ortográfica, los controles de formularios, etcétera.

En el elemento :root, la renderización con un esquema de colores también debe afectar el color de la superficie del lienzo (es decir, el color de fondo global), el valor inicial de la propiedad color y los valores usados de los colores del sistema, y también debe afectar las barras de desplazamiento de la ventana gráfica.

/*
  The page supports both dark and light color schemes,
  and the page author prefers dark.
*/
:root {
  color-scheme: dark light;
}

La metaetiqueta color-scheme

Para respetar la propiedad color-scheme de CSS, primero se debe descargar el CSS (si se hace referencia a él a través de <link rel="stylesheet">) y analizarlo. Para ayudar a los agentes de usuario a renderizar el fondo de la página con el esquema de color deseado de inmediato, también se puede proporcionar un valor color-scheme en un elemento <meta name="color-scheme">.

<!--
  The page supports both dark and light color schemes,
  and the page author prefers dark.
-->
<meta name="color-scheme" content="dark light">

Combinación de color-scheme y prefers-color-scheme

Dado que tanto la metaetiqueta como la propiedad CSS (si se aplica al elemento :root) generan el mismo comportamiento, siempre recomiendo especificar el esquema de color a través de la metaetiqueta para que el navegador pueda adoptar el esquema preferido más rápido.

Si bien para las páginas de referencia absolutas no se necesitan reglas de CSS adicionales, en el caso general, siempre debes combinar color-scheme con prefers-color-scheme. Por ejemplo, el color CSS propietario de WebKit -webkit-link, que usan WebKit y Chrome para el azul clásico de los vínculos rgb(0,0,238), tiene una proporción de contraste insuficiente de 2.23:1 sobre un fondo negro y no cumple con los requisitos de la WCAG AA ni de la WCAG AAA.

Abrí errores para Chrome, WebKit y Firefox, así como un problema de metadatos en el estándar de HTML para solucionar este problema.

Interacción con prefers-color-scheme

La interacción de la propiedad color-scheme de CSS y la etiqueta meta correspondiente con la función de medios de preferencia del usuario prefers-color-scheme puede parecer confusa al principio. De hecho, se complementan muy bien. Lo más importante que debes comprender es que color-scheme determina exclusivamente la apariencia predeterminada, mientras que prefers-color-scheme determina la apariencia que se puede diseñar. Para que esto quede más claro, supongamos la siguiente página:

<head>
  <meta name="color-scheme" content="dark light">
  <style>
    fieldset {
      background-color: gainsboro;
    }
    @media (prefers-color-scheme: dark) {
      fieldset {
        background-color: darkslategray;
      }
    }
  </style>
</head>
<body>
  <p>
    Lorem ipsum dolor sit amet, legere ancillae ne vis.
  </p>
  <form>
    <fieldset>
      <legend>Lorem ipsum</legend>
      <button type="button">Lorem ipsum</button>
    </fieldset>
  </form>
</body>

El código CSS intercalado en la página establece el background-color del elemento <fieldset> en gainsboro en el caso general y en darkslategray si el usuario prefiere un esquema de color dark según la función de medios de preferencia del usuario prefers-color-scheme.

A través del elemento <meta name="color-scheme" content="dark light">, la página le indica al navegador que admite un tema oscuro y uno claro, con una preferencia por el tema oscuro.

Según si el sistema operativo está configurado en modo oscuro o claro, toda la página aparecerá en claro sobre oscuro o viceversa, según la hoja de estilo del agente de usuario. No se incluye CSS adicional proporcionado por el desarrollador para cambiar el texto del párrafo ni el color de fondo de la página.

Observa cómo cambia el background-color del elemento <fieldset> según si el modo oscuro está habilitado, siguiendo las reglas de la hoja de estilo intercalada proporcionada por el desarrollador en la página. Puede ser gainsboro o darkslategray.

Una página en modo claro.
Modo claro: Son los diseños especificados por el desarrollador y el usuario-agente. El texto es negro y el fondo es blanco, según la hoja de estilo del agente de usuario. El background-color del elemento <fieldset> es gainsboro, según la hoja de diseño para desarrolladores intercalada.
Una página en modo oscuro.
Modo oscuro: Son los diseños especificados por el desarrollador y el usuario-agente. El texto es blanco y el fondo es negro, según la hoja de estilo del agente de usuario. El background-color del elemento <fieldset> es darkslategray, según la hoja de diseño para desarrolladores intercalada.

La apariencia del elemento <button> se controla con la hoja de estilo del agente de usuario. Su color se establece en el color del sistema ButtonText, y su background-color y los cuatro border-color se establecen en el color del sistema ButtonFace.

Página en modo claro que usa la propiedad ButtonFace.
Modo claro: El background-color y los distintos border-colors se establecen en el color del sistema ButtonFace.

Ahora observa cómo cambia el border-color del elemento <button>. El valor calculado para los interruptores border-top-color y border-bottom-color cambia de rgba(0, 0, 0, 0.847) (negruzco) a rgba(255, 255, 255, 0.847) (blanquecino), ya que el agente de usuario actualiza ButtonFace de forma dinámica según el esquema de color. Lo mismo se aplica al color del elemento <button>, que se establece en el color del sistema correspondiente ButtonText.

Muestra que los valores de color calculados coinciden con ButtonFace.
Modo claro: Los valores calculados de border-top-color y border-bottom-color, que se establecen en ButtonFace en la hoja de estilo del usuario-agente, ahora son rgba(0, 0, 0, 0.847).
Muestra que los valores de color calculados siguen coincidiendo con ButtonFace en el modo oscuro.
Modo oscuro: Los valores calculados de border-top-color y border-bottom-color que se establecen en ButtonFace en la hoja de estilo del usuario-agente ahora son rgba(255, 255, 255, 0.847).

Demostración

Puedes ver los efectos de color-scheme aplicados a una gran cantidad de elementos HTML en una demostración en Glitch. La demostración muestra deliberadamente el incumplimiento de los niveles AA y AAA de las WCAG con los colores de los vínculos que se mencionan en la advertencia anterior.

La demostración en modo claro.
La demostración se activó en color-scheme: light.
La demostración en modo oscuro.
La demostración se activó en color-scheme: dark. Observa el incumplimiento de las WCAG AA y WCAG AAA con los colores de los vínculos.

Agradecimientos

Rune Lillesveen implementó la propiedad de CSS color-scheme y la etiqueta meta correspondiente. Rune también es coeditor de la especificación del módulo de ajuste de color de CSS nivel 1. Imagen de héroe de Philippe Leone en Unsplash.