HTML/CSS lab

16 · Responsive

Dark Mode

El variant dark: aplica una clase alternativa cuando el modo oscuro está activo. La pregunta importante no es "qué clase escribo", sino "quién decide cuándo está activo" — eso depende de cómo esté configurado el proyecto.

dark: como cualquier otro variant

Se escribe la clase para modo claro normal, y se agrega dark:clase para el valor que debe tomar en modo oscuro. Funciona igual que hover: o md:, solo que la condición es el modo de color.

Modo claro
bg-white
Modo oscuro
dark:bg-stone-900
<div class="bg-white text-stone-900 dark:bg-stone-900 dark:text-white">
  Fondo blanco en claro, fondo oscuro en... oscuro
</div>

Dos formas de activarlo: media query vs. clase

Por defecto, Tailwind activa dark: según la preferencia del sistema operativo (prefers-color-scheme). La alternativa es la 'estrategia de clase': el modo oscuro se activa solo cuando existe una clase .dark en un ancestro (normalmente <html>), lo que permite un botón de toggle manual.

prefers-color-scheme (automático)
vs.
<html class="dark"> (manual)
/* Modo automático (default): sigue al sistema operativo */
/* No requiere configuración extra */

/* Modo manual con clase, en tu CSS global (Tailwind 4): */
@custom-variant dark (&:where(.dark, .dark *));

Toggle manual con JS + localStorage

Para que el modo oscuro elegido por el usuario persista entre visitas, se guarda la preferencia en localStorage y se aplica la clase 'dark' al <html> antes de que la página termine de renderizar (para evitar un parpadeo del color equivocado).

<script>
  const saved = localStorage.getItem("theme");
  const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
  const isDark = saved === "dark" || (!saved && prefersDark);
  document.documentElement.classList.toggle("dark", isDark);

  function toggleTheme() {
    const nowDark = document.documentElement.classList.toggle("dark");
    localStorage.setItem("theme", nowDark ? "dark" : "light");
  }
</script>

No es solo blanco/negro: cuidado con bordes, sombras e imágenes

Un modo oscuro completo también ajusta bordes (más sutiles sobre fondo oscuro), sombras (menos visibles, a veces se reemplazan por un borde) e íconos o imágenes que asumen fondo claro.

Card clara
shadow-md
Card oscura
border, sin shadow
<div class="bg-white dark:bg-stone-800
            border border-stone-200 dark:border-stone-700
            shadow-md dark:shadow-none">
  Card completa adaptada
</div>

<img src="/logo-light.svg" class="dark:hidden" />
<img src="/logo-dark.svg" class="hidden dark:block" />

Contraste: los mismos colores no siempre funcionan invertidos

Un texto amber-600 que se lee perfecto sobre blanco puede perder contraste sobre un fondo oscuro. En dark mode suele convenir aclarar un poco los tonos de acento (amber-400 en vez de amber-600, por ejemplo).

text-amber-600
text-amber-400
<p class="text-amber-600 dark:text-amber-400">
  Texto de acento, ajustado por modo
</p>