Modo oscuro para cualquier sitio — 4 enfoques CSS
Tu sistema operativo tiene el modo oscuro desde hace años. Tu navegador lo admite. La mayoría de las apps lo respetan. Luego abres una documentación, un blog o una intranet de 2014 — y te llevas un fondo 100% blanco a la cara a las 23 h. Cuatro métodos para resolverlo de una vez por todas.
Por qué existe este problema
El estándar CSS prefers-color-scheme está en Chrome desde 2019 y en Safari desde 2018. Tu SO conoce tu preferencia, el navegador la propaga, los sitios deberían respetarla. Deberían — en la práctica ~40% de los sitios la ignoran. Motivos: bases de código heredadas, sin presupuesto para un segundo tema, marketing que quiere la «coherencia de la marca», el autor todavía no ha llegado a ello.
Si el autor no lo hace por ti — hazlo tú. Cuatro métodos, en orden de elegancia creciente.
Método 1 — filtro universal (funciona en todo)
Un snippet, se adapta a cualquier sitio, sin necesidad de analizar el CSS específico:
html {
filter: invert(0.92) hue-rotate(180deg);
background: #1a1a1a;
}
/* Re-invertir imágenes, vídeos e iframes para que parezcan
naturales — si no, los selfies de tus amigos parecen
con un filtro de piel verde. */
img, video, picture, iframe, svg,
[style*="background-image"] {
filter: invert(1) hue-rotate(180deg);
}
Truco: invert(0.92) en lugar de invert(1) pleno da un negro más suave que un intercambio limpio blanco→negro — más descansado para los ojos. hue-rotate(180deg) corrige los colores para que el naranja siga siendo naranja (y no se vuelva azul).
Pro: funciona en todas partes, cero análisis.
Contra: sombras, degradados, grises delicados parecen raros. Algunos elementos fixed (header sticky) pueden desincronizarse durante el scroll.
Método 2 — forzar prefers-color-scheme: dark
Sitios que tienen el modo oscuro pero solo reaccionan a la preferencia del sistema. ¿Y si mantienes el SO en claro (porque estás diseñando en Figma) pero quieres la documentación de GitHub en oscuro? Sobrescribe matchMedia:
// Forzar prefers-color-scheme: dark vía JS
const dark = window.matchMedia('(prefers-color-scheme: dark)');
Object.defineProperty(dark, 'matches', {
get: () => true,
configurable: true,
});
// Notificar a los listeners (sitios enganchados vía addEventListener)
dark.dispatchEvent(new Event('change'));
Funciona en cualquier sitio que use window.matchMedia('(prefers-color-scheme: dark)') para la detección — todas las apps React/Vue modernas. No funciona en los sitios que detectan una sola vez al cargar (tendrías que recargar), o en CSS estático sin detección JS.
Método 3 — sobrescribir las custom properties CSS
Los sitios construidos sobre variables CSS (~60% de las webapps modernas) suelen tener tokens de tema como --bg-primary, --text-primary. Abre las DevTools, encuentra los nombres, sobrescribe:
/* Ejemplo: Stripe Dashboard, donde todo está basado en variables */
:root {
--color-canvas-default: #0d1117 !important;
--color-canvas-subtle: #161b22 !important;
--color-fg-default: #c9d1d9 !important;
--color-fg-muted: #8b949e !important;
--color-border-default: #30363d !important;
}
Pro: preciso, no estropea imágenes ni sombras.
Contra: 5 minutos de excavación en las DevTools para encontrar los nombres de las variables. El sitio debe usar variables CSS (comprueba: document.documentElement.style en la consola).
Método 4 — tema oscuro dedicado por sitio
Para los sitios en los que pasas horas cada día — 30 minutos para un tema a medida valen la pena. Override selectivo:
/* Tu genérica intranet corporativa */
body, .page-content, .sidebar, .top-bar {
background: #1a1a1a !important;
color: #e0e0e0 !important;
}
.card, .panel, .modal {
background: #242424 !important;
border-color: #333 !important;
}
a, a:visited { color: #58a6ff !important; }
a:hover { color: #79c0ff !important; }
input, textarea, select {
background: #1a1a1a !important;
color: #e0e0e0 !important;
border-color: #444 !important;
}
/* Tablas — lo más crítico para la legibilidad */
table th { background: #2d2d2d !important; color: #fff !important; }
table tr:nth-child(odd) { background: #1f1f1f !important; }
table tr:nth-child(even) { background: #1a1a1a !important; }
Empieza por los contenedores principales (body, page), baja hacia los componentes (card, modales), cierra con los elementos de los formularios y las tablas. Sin !important normalmente no ganas — el sitio tiene sus propios estilos con mayor especificidad.
Trampas comunes
- El
background-imageinline (p. ej.style="background: url(...)") — el filtro del método 1 no siempre lo captura. Añade[style*="background-image"]por separado. - Las sombras sobre fondo oscuro parecen halos. Quítalas (
box-shadow: none) o sustitúyelas por un acento más claro. - Los colores de la marca (logos, iconos coloreados) pierden reconocibilidad tras la inversión. Añade excepciones:
.brand-logo { filter: invert(1) hue-rotate(180deg) !important; }. - Los formularios tienen a menudo
color: blackhardcodeado inline. Sobrescribe explícitamente:input { color: #e0e0e0 !important; }. - Los elementos sticky / fixed con el filtro del método 1 pueden desincronizarse durante el scroll. Normalmente aceptable, pero conviene saberlo.
Cómo conectarlo a JustZix
- Instala JustZix (2 minutos).
- Crea una carpeta llamada «Modo oscuro».
- Regla «Modo oscuro en todas partes»: patrón de URL
*, CSS = Método 1. Ponla inactiva por defecto — actívala cuando la necesites. - Regla por sitio preferido: patrón
https://myapp.com/*, CSS = Método 3 o 4 (con tokens / selectores específicos). Siempre activa. - Conmuta toda la carpeta con un clic en el botón flotante — claro/oscuro en un solo movimiento.
Qué hacer después
La misma jerarquía (universal → preciso por sitio) vale en otras categorías de reglas — mira Ejemplos y Casos de uso. El modo oscuro es solo el caso más evidente.
Instala JustZix gratis y controla por fin el aspecto de los sitios que miras 8 horas al día.
Valora este artículo
Sin valoraciones — sé el primero.