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 metaetiqueta correspondiente permiten a los desarrolladores habilitar los valores predeterminados específicos de los temas de la hoja de estilo del usuario-agente en sus páginas.

Información general

La función de contenido multimedia de preferencias de los usuarios de prefers-color-scheme

La función de contenido multimedia de preferencias del usuario prefers-color-scheme les brinda a los desarrolladores control total sobre el aspecto de sus páginas. Si no estás familiarizado con él, lee mi artículo prefers-color-scheme: Hola oscuridad, mi viejo amigo, en el que documenté todo lo que sé sobre crear experiencias asombrosas en modo oscuro.

Una pieza de rompecabezas que se mencionó brevemente en el artículo es la propiedad de CSS color-scheme y la metaetiqueta correspondiente con el mismo nombre. Ambos facilitan tu vida como desarrollador, ya que te permiten habilitar los valores predeterminados específicos de temas de la hoja de estilo del usuario-agente en tu página, como 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

  • 76
  • 79
  • 67
  • 12.1

Origen

color-scheme

Navegadores compatibles

  • 81
  • 81
  • 96
  • 13

Origen

La hoja de estilo del usuario-agente

Antes de continuar, describiré brevemente en qué consiste una hoja de estilo de usuario-agente. La mayoría de las veces, puedes considerar 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 su nombre sugiere, 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 las de Firefox o Safari (y 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 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 la 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, se muestra una regla de CSS que usa la pseudoclase :matches y variables internas de WebKit, como -apple-system-control-background, así como la directiva #if defined del preprocesador interno de WebKit:

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 de CSS válidos. Son colores semánticos internos de WebKit.

Resulta que CSS tiene colores estandarizados del sistema semántico. Se especifican en el nivel 4 de módulo de color de CSS. Por ejemplo, Canvas (que no se debe confundir 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.

Las hojas de estilo de UA pueden usar los colores propios del sistema semántico o los estandarizados 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 configurará en blanco de manera condicional, y Canvas (o -apple-system-control-background) se establecerá en negro. A continuación, la hoja de estilo UA asigna el siguiente CSS solo una vez y abarca tanto el modo claro como 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 de módulo de ajuste de color de CSS nivel 1 presenta un modelo y controla el ajuste de color automático por parte 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 se siente cómodo cuando se renderiza. 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 conoce y puede controlar los esquemas de colores enumerados, 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 claros en primer plano.

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 coincidan con el intent del esquema de colores. Algunos ejemplos son las barras de desplazamiento, los subrayados con corrección ortográfica, 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 usados 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 cumplir con la propiedad color-scheme de CSS, es necesario descargar primero 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">

Combina color-scheme y prefers-color-scheme

Dado que tanto la metaetiqueta como la propiedad de CSS (si se aplican al elemento :root) eventualmente generan el mismo comportamiento, siempre recomiendo especificar el esquema de colores por medio de la metaetiqueta para 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 en Chrome, WebKit y Firefox, así como un metaerror en HTML estándar para solucionar este problema.

Interactúa con prefers-color-scheme

La interacción de la propiedad color-scheme de CSS y la metaetiqueta correspondiente con la función multimedia de preferencias del usuario prefers-color-scheme puede parecer confusa al principio. De hecho, juegan 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 elegante. Para que 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>

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

Mediante el 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 un tema oscuro.

Dependiendo de si el sistema operativo está configurado en modo oscuro o claro, toda la página aparece clara o oscura, o viceversa, según la hoja de estilo del usuario-agente. No hay ningún CSS adicional proporcionado por el desarrollador para cambiar el texto del párrafo o el color de fondo de la página.

Observa cómo cambia el background-color del elemento <fieldset> según esté habilitado el modo oscuro, de acuerdo con las reglas de la hoja de estilo intercalada que proporciona el desarrollador en la página. Es gainsboro o darkslategray.

Una página en modo claro.
Modo claro: estilos especificados por 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: estilos especificados por 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, mientras que su background-color y los cuatro border-color se establecen en el color del sistema ButtonFace.

Una página de modo claro que usa la propiedad ButtonFace.
Modo claro: Los objetos background-color y los distintos objetos border-color se configuran con el color de sistema ButtonFace.

Ahora, observa cómo cambia el border-color del elemento <button>. El valor calculado de 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 color de sistema correspondiente ButtonText.

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 establecieron 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 el modo oscuro.
Modo oscuro: Los valores calculados de border-top-color y border-bottom-color que se establecieron 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 aplicado a una gran cantidad de elementos HTML en una demostración en Glitch. La demostración muestra deliberadamente la incumplimiento de las WCAG AA y WCAG AAA con los colores de vínculo mencionados en la advertencia anterior.

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

Agradecimientos

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