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

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

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

La función de medios de preferencias del usuario prefers-color-scheme les brinda a los desarrolladores un control total sobre el aspecto de sus páginas. Si no lo conoces, lee mi artículo prefers-color-scheme: Hola oscuridad, mi viejo amigo, 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 CSS color-scheme y la metaetiqueta correspondiente con el mismo nombre. Ambos te facilitan la vida como desarrollador, ya que te permiten habilitar tu página para que use los valores predeterminados específicos del tema del diseño de página del usuario-agente, 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

Navegadores compatibles

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

Origen

color-scheme

Navegadores compatibles

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

Origen

La hoja de estilo del usuario-agente

Antes de continuar, permíteme describir brevemente qué es un 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. El hoja de estilo de UA determina el aspecto predeterminado de una página. Como su nombre lo indica, un diseño de plantilla de UA depende de la UA en cuestión. Puedes consultar la hoja de estilo de UA de Chrome (y de Chromium) y compararla con las de Firefox o Safari (y WebKit). Por lo general, los diseños de página de UA coinciden en la mayoría de los aspectos. Por ejemplo, todos hacen que los vínculos sean de color azul, el texto general se vuelve negro y el color de fondo es blanco, pero también hay diferencias importantes (y a veces molestas), como la forma en que definen el diseño de los controles de formularios.

Observa con más detalle el hoja de estilo de UA de WebKit y lo que hace con respecto al modo oscuro. (Busca "oscuro" en el texto completo en la hoja de estilo). El valor predeterminado que proporciona la hoja de estilo cambia según si el modo oscuro está activado o desactivado. Para ilustrar esto, aquí hay una de esas reglas de CSS que usa la pseudoclase :matches y las 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 */
}

Notará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 tiene colores del sistema semántico estandarizados. Se especifican en el nivel 4 del módulo de color CSS. Por ejemplo, Canvas (no debe confundirse con la etiqueta <canvas>) es para el fondo del contenido o los documentos de la aplicación, mientras que CanvasText es para el texto en el contenido o los documentos de la aplicación. Ambos van juntos y no deben usarse de forma aislada.

Los diseños de página de UA pueden usar sus propios colores propietarios 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á de forma condicional en blanco, y Canvas (o -apple-system-control-background) se establecerá en negro. Luego, la hoja de estilo de 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 de CSS color-scheme

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

La propiedad color-scheme que se define allí permite que un elemento indique con qué esquemas de colores es conveniente renderizarlo. Estos valores se negocian con las preferencias del usuario, lo que genera un esquema de colores elegido que afecta a aspectos de la interfaz de usuario (IU), como los colores predeterminados de los controles de formulario y las barras de desplazamiento, así como los valores usados de los colores del sistema CSS. Se admiten los siguientes valores:

  • normal: Indica que el elemento no reconoce los esquemas de colores, por lo que se debe renderizar con el esquema de colores predeterminado del navegador.

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

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

Para todos los elementos, la renderización con un esquema de colores debe hacer que los colores que se usan en toda la IU proporcionada por el navegador para el elemento coincidan con el intent del esquema de colores. Algunos ejemplos son las barras de desplazamiento, los subrayados del corrector ortográfico, los controles de formulario, 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 utilizados de los colores del sistema, y también debe afectar las barras de desplazamiento del viewport.

/*
  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 CSS color-scheme, 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 usuarios-agentes a renderizar el fondo de la página con el esquema de colores 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 aplican al elemento :root) generan el mismo comportamiento, siempre recomiendo especificar el esquema de colores a través de la metaetiqueta, de modo que el navegador pueda adoptar el esquema preferido más rápido.

Si bien para las páginas del modelo de referencia absoluto no se necesitan reglas de CSS adicionales, en general, siempre debes combinar color-scheme con prefers-color-scheme. Por ejemplo, el color -webkit-link propiedad de WebKit, que usan WebKit y Chrome para el vínculo azul clásico rgb(0,0,238), tiene una relación de contraste insuficiente de 2.23:1 sobre un fondo negro y falla tanto con el AA de WCAG como con los requisitos de WCAG AAA.

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

Interactúa con prefers-color-scheme

La interacción de la propiedad CSS color-scheme y la metaetiqueta correspondiente con la función multimedia de preferencia del usuario prefers-color-scheme puede parecer confusa al principio. De hecho, funcionan muy bien juntos. Lo más importante que debes comprender es que color-scheme determina exclusivamente la apariencia predeterminada, mientras que prefers-color-scheme determina la apariencia con diseño. Para que esto sea 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 colores dark según la función multimedia 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 preferencia por el tema oscuro.

Según si el sistema operativo está configurado en modo oscuro o claro, toda la página aparecerá en modo claro sobre oscuro o viceversa, según la hoja de estilo del usuario-agente. No hay 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 del hoja de estilo intercalado que proporciona el desarrollador en la página. Es gainsboro o darkslategray.

Una página en modo claro.
Modo claro: Son los estilos que especifican el desarrollador y el usuario-agente. El texto es negro y el fondo es blanco según la hoja de estilo del usuario-agente. El background-color del elemento <fieldset> es gainsboro según la hoja de estilo del desarrollador intercalada.
Una página en modo oscuro.
Modo oscuro: Son los estilos que especifican el desarrollador y el usuario-agente. El texto es blanco y el fondo es negro según la hoja de estilo del usuario-agente. El background-color del elemento <fieldset> es darkslategray según la hoja de estilo del desarrollador intercalada.

La hoja de estilo del usuario-agente controla el aspecto del elemento <button>. 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.

Una página en modo claro que usa la propiedad ButtonFace.
Modo claro: background-color y los diversos border-color se establecen en el color del sistema ButtonFace.

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

Se 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).
Se muestra que los valores de color calculados aún coinciden con ButtonFace en 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 demo en Glitch. La demostración de forma deliberada muestra la incumplimiento de WCAG AA y WCAG AAA con los colores de los vínculos mencionados en la advertencia anterior.

La demostración en modo claro.
La demo se activó en color-scheme: light.
La demostración en modo oscuro.
La demo se activó en color-scheme: dark. Ten en cuenta que las WCAG AA y WCAG AAA incumplen con los colores de los vínculos.

Agradecimientos

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