El "modo oscuro" o "dark mode" se ha convertido en una característica de interfaz de usuario esencial en muchos sistemas operativos y aplicaciones web. Originario de sistemas como macOS Mojave, que ofrecía a los usuarios la opción entre un tema claro y uno oscuro, este concepto ha ganado popularidad debido a sus múltiples beneficios. Científicamente, los temas con bajo contraste y colores oscuros pueden reducir la fatiga visual al disminuir la emisión de luz azul y el brillo general de la pantalla, lo que es especialmente útil en entornos con poca luz. Además, en dispositivos con pantallas OLED, el modo oscuro puede contribuir a un menor consumo de energía.
Tradicionalmente, la implementación de temas en la web se lograba mediante la carga dinámica de archivos CSS alternativos a través de JavaScript. Este enfoque, aunque funcional, presentaba desafíos de mantenimiento, especialmente al escalar a múltiples temas o al realizar cambios en la estructura de estilos, lo que podía resultar en una gestión de código redundante y compleja. Herramientas de preprocesamiento como Sass mitigaron parte de esta complejidad al permitir la definición de variables, pero la interacción directa con el DOM seguía siendo limitada.
La introducción de las propiedades personalizadas de CSS, a menudo denominadas variables CSS, revolucionó la forma en que se pueden gestionar los temas. Estas variables permiten declaarr valores reutilizables directamente en CSS y, lo que es más importante, pueden ser modificadas dinámicamente mediante JavaScript, ofreciendo una solución elegante y nativa para la gestión de temas, incluido el modo oscuro.
Uso Básico de Propiedades Personalizadas de CSS
Las propiedades personalizadas se definen utilizando la sintaxis --nombre-variable: valor;. Se suelen declarar dentro del selector :root para hacerlas accesibles globalmente a todo el documento. Se utilizan con la función var().
:root {
--color-principal: #3498db; /* Un color de ejemplo */
--fondo-pagina: #ffffff;
}
.element-header {
color: var(--color-principal);
}
.container-body {
background-color: var(--fondo-pagina);
}
Es posible proporcionar un valor de respaldo opcional en caso de que la variable no esté definida. Esto asegura que se aplique un estilo por defecto si la variable falla o no se carga correctamente:
.widget-card {
border-left: 5px solid var(--color-principal, #2ecc71); /* Usa --color-principal, si no, usa #2ecc71 */
}
Interacción con Propiedades Personalizadas desde JavaScript
Una de las mayores ventajas es la capacidad de leer y modificar estas variables directamente con JavaScript. Esto es fundamental para cambiar dinámicamente el tema de un sitio web.
Obtener el valor de una variable CSS:
const estilosRaiz = getComputedStyle(document.documentElement);
const colorActual = estilosRaiz.getPropertyValue("--color-principal").trim();
console.log(`El color principal actual es: ${colorActual}`);
Establecer (modificar) el valor de una variable CSS:
document.documentElement.style.setProperty("--color-principal", "#e74c3c"); // Cambiar el color principal a rojo
Implementación de Modo Oscuro con Propiedades Personalizadas
Aplicando este principio, para implementar un modo oscuro, solo necesitamos definir un conjunto de variables CSS para el tema claro y otro para el tema oscuro. Luego, una función JavaScript se encargará de cambiar estos valores en el elemento raíz del documento.
Primero, definamos las variables CSS iniciales (tema claro por defecto):
:root {
--bg-color-primary: #ffffff; /* Fondo principal */
--text-color-primary: #333333; /* Color de texto principal */
--link-color: #007bff; /* Color de enlaces */
--header-logo-image: url('assets/logo-light.png'); /* Imagen de logo para tema claro */
}
Luego, usamos estas variables en nuestros estilos:
body {
background-color: var(--bg-color-primary);
color: var(--text-color-primary);
}
a {
color: var(--link-color);
}
.site-logo {
background-image: var(--header-logo-image);
}
Finalmente, una función JavaScript para alternar entre los temas y guardar la preferencia del usuario en localStorage:
function aplicarTema(esModoOscuroActivo) {
const estilosDocumento = document.documentElement.style;
if (esModoOscuroActivo) {
estilosDocumento.setProperty("--bg-color-primary", "#1e1e1e");
estilosDocumento.setProperty("--text-color-primary", "#e0e0e0");
estilosDocumento.setProperty("--link-color", "#90caf9");
estilosDocumento.setProperty("--header-logo-image", "url('assets/logo-dark.png')");
localStorage.setItem("temaPreferido", "dark");
} else {
estilosDocumento.setProperty("--bg-color-primary", "#ffffff");
estilosDocumento.setProperty("--text-color-primary", "#333333");
estilosDocumento.setProperty("--link-color", "#007bff");
estilosDocumento.setProperty("--header-logo-image", "url('assets/logo-light.png')");
localStorage.setItem("temaPreferido", "light");
}
}
document.addEventListener("DOMContentLoaded", () => {
const interruptorTema = document.getElementById("tema-alternar"); // Suponiendo un checkbox o botón de alternancia
// Cargar preferencia de tema guardada al cargar la página
const temaGuardado = localStorage.getItem("temaPreferido");
if (temaGuardado === "dark") {
if (interruptorTema) interruptorTema.checked = true;
aplicarTema(true);
} else {
if (interruptorTema) interruptorTema.checked = false;
aplicarTema(false); // Por defecto, tema claro si no hay preferencia o es "light"
}
// Escuchar cambios en el interruptor de tema
if (interruptorTema) {
interruptorTema.addEventListener("change", (evento) => {
aplicarTema(evento.target.checked);
});
}
});
Este método simplifica drásticamente la gestión de temas, permitiendo un control centralizado y dinámico de los estilos a través de JavaScript y las propiedades personalizadas de CSS, al mismo tiempo que utiliza Web Storage (localStorage) para recordar la elección del usuario entre sesiones.