MAISON CODE .
/ Tech · UX · Design · Dark Mode · Accessibility

Modo oscuro: no se trata solo de invertir colores

Los usuarios esperan el modo oscuro. Implementarlo ingenuamente conduce a un bajo contraste y fatiga visual. Cómo diseñar un sistema de color semántico que se adapte con gracia.

AB
Alex B.
Modo oscuro: no se trata solo de invertir colores

Por qué Maison Code habla de esto

En Maison Code Paris, actuamos como la conciencia arquitectónica de nuestros clientes. A menudo heredamos stacks “modernos” construidos sin una comprensión fundamental de la escala.

Discutimos este tema porque representa un punto de inflexión crítico en la madurez de la ingeniería. Implementarlo correctamente diferencia un MVP frágil de una plataforma resistente de nivel empresarial.

La expectativa de la oscuridad

En 2020, el modo oscuro fue “agradable tenerlo”. En 2025, es un requisito. iOS, Android, macOS y Windows admiten el modo oscuro en todo el sistema. Si su usuario tiene su teléfono configurado en Modo Oscuro (para ahorrar batería o proteger sus ojos durante la noche), abre su sitio web y recibe una explosión de luz blanca #FFFFFF… Cierran la pestaña. Es físicamente doloroso. Modo oscuro no es una característica; es Empatía del usuario.

Por qué Maison Code habla del modo oscuro

En Maison Code, nos esforzamos por lograr “una experiencia perfecta”. Nos aseguramos de que los sitios de nuestros clientes respeten las preferencias del sistema del usuario automáticamente (“prefiere-color-scheme”). Pero lo más importante es que entendemos que el modo oscuro es un desafío de marca. Las marcas de lujo confían en colores específicos. ¿Cómo se traduce “Chanel Black on White” al modo oscuro sin perder la identidad? Manejamos esta traducción semántica a diario. No nos limitamos a “invertir colores”. “Reinterpretamos” la marca para ambientes con poca luz.

La estrategia de ingeniería: variables CSS + HSL

(Ver Variables CSS). El enfoque ingenuo es: body.dark { fondo: negro; color: blanco; }. Esto parece terrible. El negro puro (#000) provoca “manchas” en las pantallas OLED al desplazarse. El texto en blanco puro (#FFF) sobre negro puro provoca fatiga visual (halación).

El enfoque semántico: Definimos colores usando HSL (Tono, Saturación, Luminosidad). Esto nos permite modificar la luminosidad mediante programación.

:raíz {
  /* Tono de marca (por ejemplo, azul) */
  --marca-h: 210;
  --marcas: 100%;
  
  /* Modo de luz */
  --bg-l: 100%;
  --texto-l: 10%;
  
  --bg-color: hsl(var(--brand-h), 10%, var(--bg-l));
  --text-color: hsl(var(--brand-h), 10%, var(--text-l));
}

[tema-datos="oscuro"] {
  /* Modo oscuro: simplemente cambia la luminosidad */
  --bg-l: 10%;
  --texto-l: 90%;
}

Observe que no elegimos simplemente “Negro”. Elegimos un “Azul muy oscuro” (“hsl(210, 10%, 10%)`). Esto conserva el tinte de la marca incluso en modo oscuro. Se siente más rico y premium que el gris mate.

Implementación técnica: la palanca y el parpadeo

La parte más difícil del modo oscuro es el FOUC (Flash of Unstyled Content) o Flash of White.

  1. El usuario carga la página (el servidor envía HTML).
  2. El navegador muestra el fondo blanco de forma predeterminada.
  3. Se carga JS, lee localStorage, ve “Oscuro”.
  4. JS agrega la clase .dark.
  5. La página parpadea en negro. Este destello de una fracción de segundo destruye la experiencia del usuario.

La solución: un script de bloqueo en <head>. Debes inyectar un pequeño script antes de que se cargue el CSS.

<cabeza>
  <guión>
    (función() {
      const almacenado = localStorage.getItem('tema');
      const system = window.matchMedia('(prefiere-color-esquema: oscuro)').matches;
      if (almacenado === 'oscuro' || (!almacenado && sistema)) {
        document.documentElement.classList.add('oscuro');
      }
    })();
  </script>
</cabeza>

Debido a que este script está en el encabezado y bloqueando, el navegador lo ejecuta antes de la primera pintura. La página se muestra inicialmente como Oscura. Cero parpadeo.

Diseñar para la profundidad

En el Modo Luz, usamos Sombras para mostrar la profundidad (Tarjetas flotando en el fondo). En el modo oscuro, las sombras son invisibles (sombra oscura sobre fondo oscuro). Solución: Utilice Luminosidad para mostrar profundidad.

  • Antecedentes: Nivel 0 (Más oscuro).
  • Tarjeta: Nivel 1 (Un poco más claro).
  • Modal: Nivel 2 (Más ligero).
  • Botón: Nivel 3 (Más ligero). En lugar de “Sombras”, utilizamos “superposiciones” o ligeros cambios de color de fondo.

Imágenes y modo oscuro

Las imágenes brillantes en el modo oscuro pueden resultar discordantes. Consejo: Reduzca ligeramente el brillo y el contraste de las imágenes cuando esté en modo oscuro.

[tema-datos="oscuro"] img {
  filtro: brillo (0,8) contraste (1,2);
}

Esto hace que las imágenes se combinen mejor con la interfaz oscura.

La visión del escéptico

“El modo oscuro es una moda pasajera. Me gusta el papel blanco”. Contrapunto:

  1. Batería: En las pantallas OLED (iPhone X+), los píxeles oscuros están apagados. El modo oscuro ahorra aproximadamente un 30% de duración de la batería.
  2. Salud: Reducir la exposición a la luz azul durante la noche ayuda a la higiene del sueño.
  3. Elección: Dale al usuario la opción. Si fuerza el Modo Luz, es arrogante.

Preguntas frecuentes

P: ¿Debo usar un botón de alternancia? R: Sí. Detecte automáticamente “prefiere el esquema de color” primero, pero permita la anulación por parte del usuario. Colóquelo en el pie de página o en el encabezado.

P: ¿Invertir logotipos? R: Si su logotipo es texto negro, desaparece en el modo oscuro. Necesita un logotipo SVG que herede currentColor, o necesita intercambiar la fuente de la imagen (logo-dark.png).

11. Manejo avanzado de iconos (SVGcurrentColor)

Deja de exportar iconos PNG negros. Utilice SVG en línea con fill="currentColor". Esto hace que el icono herede el color del texto de su padre. Si el texto principal es blanco (modo oscuro), el icono es blanco. Si el texto principal es negro (modo claro), el icono es negro. Esto elimina la necesidad de duplicados de icon-dark.svg y icon-light.svg. Un activo. Temas infinitos.

12. Preferencia persistente sin FOUC

El debate entre “cookies” y “almacenamiento local”. Si utiliza la representación del lado del servidor (Next.js), localStorage no está disponible en el servidor. Entonces el servidor muestra el modo ligero. El cliente hidrata el modo oscuro. Parpadeo. Solución: Galletas. Cuando el usuario cambia el tema, configure una cookie theme=dark. Lea esta cookie en middleware.ts o getServerSideProps. Inyecte <html class="dark"> en el servidor. Ahora llega el HTML ya Oscuro. Primera pintura perfecta.

13. Accesibilidad: Relaciones de contraste (WCAG)

El modo oscuro suele ser más difícil de leer para el astigmatismo. “Halation” (efecto halo) ocurre con texto blanco sobre fondo negro. Regla: Nunca uses negro puro (#000000). Utilice gris oscuro (#121212 o similar). Reduce la fatiga visual. Pruebas: utilice el selector “Contraste” de Chrome DevTools. Asegúrese de que su texto cumpla con el Estándar AA (4.5:1). A menudo, su “Marca Azul” funciona en blanco pero falla en negro. Necesitas --brand-text-dark (un azul más claro) específicamente para texto en modo oscuro.

14. Manejo dinámico de los cambios en el tema del sistema

El usuario cambia su Mac de claro a oscuro mientras navega. ¿Su sitio se adapta al instante? Utilice el detector de eventos change en matchMedia.

window.matchMedia('(prefiere-esquema-de-colores: oscuro)').addEventListener('cambiar', e => {
    const nuevoColorScheme = e.matches? "oscuro": "claro";
    // Solo actualiza si el usuario no ha anulado explícitamente la lógica
    if (!localStorage.getItem('tema')) {
        document.documentElement.classList.toggle('dark', e.matches);
    }
});

Esto permite esa sensación “mágica” en la que el sitio web respira con el sistema operativo.

15. Optimización OLED (negro verdadero versus gris)

Hay un debate. Negro puro (#000000) desactiva los píxeles. Ahorra batería máxima. Gris oscuro (#121212) es mejor para la legibilidad del texto y reduce las manchas OLED (rastro morado al desplazarse). Veredicto del código de Maison: utilice gris oscuro para superficies (tarjetas, fondos) y negro puro para bordes o espacios negativos. Esto le brinda la “sensación premium” sin artefactos visuales. También utilizamos meta name="theme-color" para teñir la barra del navegador Safari para que coincida con su fondo, creando una experiencia similar a la de una aplicación sin bordes.

16. Detección de temas del lado del servidor (sugerencias para el cliente)

Las galletas son buenas. Las sugerencias para el cliente son mejores. Sec-CH-Prefiere-Esquema-de-colores. Si el navegador envía este encabezado, el servidor sabe que el usuario prefiere el modo oscuro sin leer una cookie. Este es el santo grial. Permite que la primera visita (sin cookies) esté perfectamente temática. Maison Code implementa este estándar de vanguardia para que nuestros clientes garanticen Zero-Flicker en el primer byte.

17. ¿Por qué Código Maison?

En Maison Code, no nos limitamos a “cambiar los colores”. Rediseñamos la Identidad de marca para entornos con poca luz. Auditamos las relaciones de contraste para garantizar el cumplimiento de la accesibilidad (ADA/WCAG). Implementamos el script “Flicker-Free” para garantizar que sus usuarios nunca reciban flash. Creemos que el Modo Oscuro es un ejercicio de empatía. Demuestra que te preocupas por cómo tu usuario consume tu contenido.

17. Conclusión

El modo oscuro no se trata de cambiar colores. Se trata de comprobar las relaciones de contraste (WCAG AA), gestionar la percepción de profundidad y respetar el contexto del usuario. Bien implementado, por la noche se siente como el interior de un automóvil de lujo. Si se implementa mal, parece un símbolo del sistema roto. No dejes que tu marca parezca rota el 50% del tiempo.


¿Cegando a tus usuarios?

Implementamos el modo oscuro del sistema sin parpadeos que respeta la duración de la batería y los ojos del usuario. Contrate a nuestros arquitectos.