Addaw, ir a inicio Donar

Lección 4 de 10 · 14 min de lectura · Revisado el 26/10/2026

Preferencias del usuario en CSS: colores forzados, contraste y modo oscuro

Cada vez más personas ajustan su sistema operativo para ver mejor: un tema de contraste en Windows, el modo oscuro en el móvil, «aumentar contraste» en macOS, un tamaño de letra mayor en el navegador. El navegador traslada esas preferencias a la web, y el CSS puede respetarlas o pisarlas. En el curso de color y contraste viste estos modos desde el diseño; esta lección te da el código para que la interfaz se adapte sin perder información, con especial atención al modo de colores forzados, el que más webs rompe. El movimiento reducido tiene lección propia, la siguiente.

Las preferencias que el sistema expone a la web

Las preferencias se consultan con media features (características de medio) dentro de @media, igual que el ancho de pantalla:

CaracterísticaValoresQué la activaQué debe hacer tu CSS
forced-colorsnone, activeTemas de contraste de Windows (soportado en navegadores Chromium y Firefox)Dejar que el sistema pinte y asegurar bordes, foco e iconos
prefers-contrastno-preference, more, less, custom«Aumentar contraste» en macOS e iOS, entre otros ajustesReforzar bordes, quitar transparencias y grises tenues
prefers-color-schemelight, darkModo claro u oscuro del sistemaOfrecer un tema oscuro que cumpla el mismo contraste
prefers-reduced-motionno-preference, reduce«Reducir movimiento»Quitar el movimiento espacial (lección siguiente)

A ellas se suma una preferencia que no es una media query: el tamaño de letra por defecto del navegador, que solo se respeta si usas rem y em, como vimos en la primera lección.

Infografía · Conceptos clave

Seis preferencias del usuario que tu CSS debe respetar

Cada ajuste del sistema llega a la web como una media query, una propiedad o una unidad

  • forced-colorsTemas de contraste: bordes y contornos transparentes, colores del sistema
  • prefers-contrastCon «more», refuerza bordes y quita grises tenues y transparencias
  • prefers-color-schemeTema oscuro con el mismo contraste que el claro: 4,5:1 y 3:1
  • color-schemeAdapta controles nativos y barras de desplazamiento al tema
  • prefers-reduced-motionSustituye el movimiento espacial por fundidos o elimínalo
  • Tamaño de letra baseSolo se respeta con rem y em, no con fuentes en píxeles
ADDAW · Cursos de accesibilidad
Leer la infografía como texto

Seis tarjetas, cada una con una preferencia y lo que debe hacer el CSS. forced-colors: con los temas de contraste de Windows, usa bordes y contornos transparentes y colores del sistema. prefers-contrast: con el valor more, refuerza bordes y elimina grises tenues y transparencias. prefers-color-scheme: el tema oscuro debe cumplir el mismo contraste que el claro, 4,5:1 para texto y 3:1 para componentes. color-scheme: esta propiedad adapta los controles nativos y las barras de desplazamiento al tema. prefers-reduced-motion: sustituye el movimiento espacial por fundidos o elimínalo. Tamaño de letra base del navegador: solo se respeta con unidades rem y em, no con fuentes en píxeles.

El modo de colores forzados a fondo

Cuando una persona activa un tema de contraste en Windows (por ejemplo, fondo negro con texto amarillo, o el tema «Desierto» de fondo claro), el navegador sustituye los colores de la página por una paleta reducida que ella ha elegido. Lo usan personas con baja visión, con fotofobia, con migraña o con dificultades de lectura. Lo que ocurre con tu CSS:

  • Los colores de texto, fondo, bordes y contornos se sustituyen por los del sistema. Tus colores de marca desaparecen; es lo que la persona ha pedido.
  • box-shadow y text-shadow se eliminan.
  • Los degradados de fondo desaparecen; las imágenes con url() se mantienen, y el navegador pinta un fondo opaco detrás del texto para que siga siendo legible.
  • Los controles nativos (button, input, select) se redibujan con los colores del sistema y siguen siendo reconocibles.

Los problemas aparecen cuando la interfaz transmite forma, estado o información solo con colores de fondo o sombras: un botón que es «un rectángulo azul» sin borde se convierte en texto suelto; una casilla de verificación personalizada hecha con un div coloreado pierde su marca; una barra de progreso o un indicador de estado verde o rojo desaparecen; el foco hecho con box-shadow se esfuma.

Ejemplo

El truco de los bordes transparentes: invisibles en modo normal, el sistema los pinta en modo forzado.

.boton {
  background: #0b5394;
  color: #ffffff;
  border: 2px solid transparent;   /* aparece con colores forzados */
}
.boton:focus-visible {
  outline: 3px solid transparent;  /* idem para el foco */
  box-shadow: 0 0 0 3px #ffbf47;   /* lo que se ve en modo normal */
}
.icono { fill: currentColor; }     /* el icono hereda el color del texto */

@media (forced-colors: active) {
  .tarjeta-seleccionada { border: 3px solid Highlight; }
  .estado-activo { border-left: 4px solid CanvasText; } /* marca que no depende del fondo */
  .muestra-color { forced-color-adjust: none; } /* aquí el color es el contenido */
}

Dentro de forced-colors: active no uses colores concretos, que el sistema volvería a sustituir, sino colores del sistema: palabras clave de CSS que toman el valor del tema activo. Las más útiles son Canvas y CanvasText (fondo y texto), LinkText (enlaces), ButtonFace, ButtonText y ButtonBorder (botones), Highlight y HighlightText (selección y elementos activos) y GrayText (deshabilitado). Así, un estado «seleccionado» puede marcarse con un borde Highlight grueso en lugar de con un fondo de color.

Los iconos SVG con colores fijos en el atributo fill pueden quedar invisibles sobre el fondo del sistema (un icono negro sobre fondo negro). Con fill: currentColor heredan el color del texto y se adaptan solos. Las imágenes de mapa de bits no se tocan: un logotipo con texto oscuro sobre transparencia puede desaparecer sobre un tema oscuro, igual que en el modo oscuro que verás más abajo.

Error frecuente

Aplicar forced-color-adjust: none a toda la web «para conservar la imagen de marca». Anula precisamente la adaptación que la persona necesita y suele dejar textos ilegibles. Esa propiedad está pensada para casos puntuales en los que el color es el contenido (muestras de color de un producto, un selector de color) y, aun entonces, el texto que acompaña debe seguir siendo legible. Tampoco uses la antigua media query -ms-high-contrast: está obsoleta y los navegadores actuales la ignoran.

prefers-contrast: más contraste cuando se pide

prefers-contrast: more se activa cuando la persona pide más contraste sin llegar a forzar los colores. No sirve para cumplir 1.4.3 Contraste (mínimo): la versión por defecto ya debe cumplirlo. Es una mejora para quien necesita aún más:

@media (prefers-contrast: more) {
  :root { --texto-secundario: #1a1a1a; --borde: #000000; }
  .campo { border-width: 2px; }
  .cabecera { background: #ffffff; backdrop-filter: none; } /* fuera transparencias */
  .placeholder-sutil::placeholder { color: #333333; }
}

Buenos candidatos para reforzar: textos grises secundarios, bordes finos de campos y tarjetas, fondos semitransparentes o con desenfoque, texto sobre fotografías y separadores tenues.

Modo oscuro sin romper la accesibilidad

Un tema oscuro bien hecho empieza por organizar los colores en variables (los tokens de diseño) y redefinirlas, no por reescribir cada regla:

:root {
  color-scheme: light dark;  /* controles nativos y barras de desplazamiento se adaptan */
  --fondo: #ffffff;  --texto: #1a1a1a;  --enlace: #0b5394;  --foco: #1a1a1a;
}
@media (prefers-color-scheme: dark) {
  :root { --fondo: #121212; --texto: #e8e8e8; --enlace: #8ab4f8; --foco: #ffffff; }
}
body { background: var(--fondo); color: var(--texto); }
a { color: var(--enlace); }

Si el tema oscuro se aplica automáticamente según la preferencia del sistema, para esa persona es la página: debe cumplir 1.4.3, 1.4.11 Contraste no textual y 1.4.1 Uso del color igual que el tema claro. Mide el contraste en los dos temas, incluidos el indicador de foco, los bordes de los campos y los mensajes de error, y revisa estos fallos típicos:

  • Logotipos e imágenes PNG con partes oscuras sobre transparencia que desaparecen sobre fondo oscuro. Solución: una versión clara con <picture> y <source media="(prefers-color-scheme: dark)">, o un fondo propio en la imagen.
  • Sombras como única separación entre tarjetas: sobre fondo oscuro no se ven; usa bordes o cambios de luminosidad.
  • Colores de marca muy saturados que sobre negro vibran o no contrastan; necesitan una variante más clara.
  • Gráficos y mapas con colores pensados para fondo blanco.

Si ofreces un selector de tema propio, respeta por defecto la preferencia del sistema, guarda la elección en localStorage, aplícala antes de pintar la página (para evitar el destello del tema contrario) y haz el selector accesible: un grupo de botones de opción «Claro, Oscuro, Según el sistema» o un botón con aria-pressed. La función light-dark(), más reciente, permite escribir los dos valores en una sola declaración; compruébala en los navegadores que debas soportar antes de depender de ella.

Cómo comprobarlo

  • En Chrome y Edge, abre las herramientas de desarrollo, menú «More tools», panel «Rendering»: permite emular prefers-color-scheme, prefers-contrast, forced-colors y prefers-reduced-motion sin cambiar el sistema.
  • La emulación no sustituye a la prueba real: en Windows, activa un tema de contraste (Configuración, Accesibilidad, Temas de contraste) y recorre la web con el teclado.
  • Busca en el CSS box-shadow usados como foco o borde, background que transmite estado y fill con colores fijos en los SVG.
  • Mide el contraste del tema oscuro con el mismo rigor que el del claro.

Pruébalo tú

En un ordenador con Windows, pulsa Alt izquierda + Mayús izquierda + Impr Pant para activar o desactivar el contraste alto (Windows pedirá confirmación). Abre la web de tu organización y localiza tres cosas: un botón que haya perdido su forma, un icono que haya desaparecido y un control cuyo foco ya no se vea. Vuelve a pulsar la combinación para salir.

Punto clave

Las preferencias del sistema son decisiones de la persona, no caprichos que la marca deba corregir. Diseña para que la forma, el estado y el foco no dependan solo del color de fondo ni de las sombras: bordes y contornos transparentes, currentColor en los iconos, colores del sistema en modo forzado y el mismo contraste en el tema oscuro que en el claro.

Resumen

  • forced-colors, prefers-contrast y prefers-color-scheme exponen preferencias del sistema; el tamaño de letra se respeta con rem.
  • En colores forzados desaparecen las sombras y los degradados: usa bordes y contornos transparentes, fill: currentColor y colores del sistema como Highlight o CanvasText.
  • Reserva forced-color-adjust: none para cuando el color es el contenido.
  • prefers-contrast: more es un refuerzo, no la forma de cumplir 1.4.3.
  • El tema oscuro debe cumplir el mismo contraste; organízalo con variables y color-scheme, y prueba con emulación y con un tema de contraste real.

Comprueba lo que has aprendido

Esta lección se puede leer libremente. Para hacer su test de 3 preguntas, los ejercicios prácticos con páginas reales, guardar tu avance y optar al examen y al certificado, matricúlate en el curso.