Función CSS light-dark(): Cambio de Tema Nativo
Embed This Widget
Add the script tag and a data attribute to embed this widget.
Embed via iframe for maximum compatibility.
<iframe src="https://colorfyi.com/iframe/entity//" width="420" height="400" frameborder="0" style="border:0;border-radius:10px;max-width:100%" loading="lazy"></iframe>
Paste this URL in WordPress, Medium, or any oEmbed-compatible platform.
https://colorfyi.com/entity//
Add a dynamic SVG badge to your README or docs.
[](https://colorfyi.com/entity//)
Use the native HTML custom element.
La implementación del modo oscuro ha requerido históricamente una cantidad no trivial de código repetitivo: una media query prefers-color-scheme que sobreescribe cada propiedad personalizada, JavaScript para manejar los interruptores del usuario, localStorage para persistir las preferencias, y un script en línea en <head> para evitar el destello del tema incorrecto al cargar la página. La función CSS light-dark() no elimina todo esto, pero reduce dramáticamente la superficie CSS del problema.
light-dark() es una función de color CSS que toma exactamente dos valores de color y devuelve el primero cuando el esquema de color activo es claro, o el segundo cuando el esquema de color activo es oscuro. Es el equivalente CSS semántico del operador ternario para colores.
¿Qué Es light-dark()?
La firma de la función es simple:
color: light-dark(<light-color>, <dark-color>);
Cuando el esquema de color activo es claro, el navegador usa <light-color>. Cuando es oscuro, usa <dark-color>. El "esquema de color activo" está determinado por la propiedad CSS color-scheme, que a su vez responde a la media query del sistema prefers-color-scheme o a un valor explícito establecido en un elemento.
La función está soportada en:
- Chrome/Edge: desde la versión 123 (marzo de 2024)
- Firefox: desde la versión 120 (noviembre de 2023)
- Safari: desde la versión 17.5 (junio de 2024)
El soporte global es alrededor del 85% a principios de 2026. Es una adición relativamente reciente, pero la cobertura de navegadores está creciendo lo suficientemente rápido como para usarla en producción con una estrategia de fallback.
Cómo Funciona con la Propiedad color-scheme
light-dark() no funciona de forma aislada. Depende completamente de que la propiedad CSS color-scheme esté configurada correctamente. Sin ella, la función no tiene contexto para decidir qué valor devolver.
La propiedad color-scheme declara qué esquemas de color soporta un documento o elemento. Establecerla en :root es el punto de partida:
:root {
color-scheme: light dark;
}
Esta única declaración le dice al navegador que tu página soporta tanto esquemas de color claro como oscuro. El navegador entonces:
- Lee la preferencia del sistema
prefers-color-schemedel usuario - Aplica el esquema correspondiente
- Hace que todas las llamadas
light-dark()en la página se resuelvan al valor apropiado
Con esto en su lugar, definir colores con reconocimiento del tema se convierte en una cuestión de escribir declaraciones únicas:
:root {
color-scheme: light dark;
--color-background: light-dark(#FFFFFF, #0F0F17);
--color-text: light-dark(#1A1A2E, #E8E8F0);
--color-border: light-dark(#DEE2E6, #2E2E4A);
--color-accent: light-dark(#2563EB, #60A5FA);
}
Sin media query. Sin sobrescrituras de selector. Una declaración por color, ambos valores en línea. El navegador maneja el cambio automáticamente según la preferencia del sistema.
Restringiendo a un Solo Esquema
Establecer color-scheme: light o color-scheme: dark fuerza un solo esquema independientemente de la preferencia del sistema:
/* Siempre claro, independientemente de la preferencia del SO */
.widget {
color-scheme: light;
background: light-dark(#FFFFFF, #0F0F17);
/* Siempre se resuelve a #FFFFFF */
}
/* Siempre oscuro */
.dark-panel {
color-scheme: dark;
color: light-dark(#1A1A2E, #E8E8F0);
/* Siempre se resuelve a #E8E8F0 */
}
Esto es útil para componentes de UI que siempre deben aparecer en un modo específico — por ejemplo, un editor de código que siempre debe tener un fondo oscuro independientemente del tema de la página circundante.
La Palabra Clave only
Añadir only evita que la cascada sobreescriba el esquema para ese elemento:
.forced-light {
color-scheme: only light;
}
Esto es principalmente útil cuando tienes un elemento dentro de un contexto de modo oscuro que debe permanecer claro.
Reemplazando Media Queries de prefers-color-scheme
El enfoque tradicional del modo oscuro usando media queries requiere duplicar o sobreescribir cada variable de color:
/* Enfoque tradicional — verboso */
:root {
--bg: #FFFFFF;
--text: #1A1A2E;
--accent: #2563EB;
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #0F0F17;
--text: #E8E8F0;
--accent: #60A5FA;
}
}
Con light-dark(), esto se colapsa a:
/* Enfoque light-dark() — una declaración por variable */
:root {
color-scheme: light dark;
--bg: light-dark(#FFFFFF, #0F0F17);
--text: light-dark(#1A1A2E, #E8E8F0);
--accent: light-dark(#2563EB, #60A5FA);
}
Las variables en sí mismas se vuelven autodescriptivas. Cuando lees --accent: light-dark(#2563EB, #60A5FA), ves inmediatamente ambos valores y entiendes la relación. El enfoque de media query dispersa los valores claro y oscuro en dos bloques separados, lo que hace que auditar y actualizar la paleta sea más difícil.
Cuándo las Media Queries Siguen siendo Necesarias
La media query prefers-color-scheme sigue siendo necesaria para adaptaciones no relacionadas con el color que cambian según el tema:
@media (prefers-color-scheme: dark) {
/* Ajustes no relacionados con el color que light-dark() no puede expresar */
img.logo {
filter: invert(1) brightness(1.2);
}
.hero-image {
opacity: 0.85;
}
}
Para cualquier cosa que sea puramente un cambio de color, light-dark() es más limpio. Para adaptaciones estructurales o no relacionadas con el color (filtros de imagen, opacidad, propiedades de visualización), la media query sigue siendo la herramienta correcta.
Combinando con Propiedades Personalizadas CSS
light-dark() funciona dentro de valores de propiedades personalizadas, que es donde emerge todo su poder. Defines todos los colores con reconocimiento del tema en :root, y cada componente de la página hace referencia a estas variables. Cuando el esquema de color cambia, todo se actualiza simultáneamente.
Ejemplo de Sistema de Tema Completo
:root {
color-scheme: light dark;
/* Fondos */
--color-bg-base: light-dark(#FFFFFF, #0F0F17);
--color-bg-elevated: light-dark(#F8F9FA, #1A1A2E);
--color-bg-overlay: light-dark(#F1F3F5, #252540);
/* Texto */
--color-text-primary: light-dark(#1A1A2E, #E8E8F0);
--color-text-secondary: light-dark(#4A4A6A, #A8A8C0);
--color-text-muted: light-dark(#6C757D, #6A6A88);
--color-text-inverse: light-dark(#FFFFFF, #1A1A2E);
/* Bordes */
--color-border: light-dark(#DEE2E6, #2E2E4A);
--color-border-strong: light-dark(#ADB5BD, #4A4A6A);
/* Interactivo / marca */
--color-accent: light-dark(#2563EB, #60A5FA);
--color-accent-hover: light-dark(#1D4ED8, #93C5FD);
--color-accent-subtle: light-dark(#DBEAFE, #1E3A5F);
/* Retroalimentación */
--color-success: light-dark(#16A34A, #4ADE80);
--color-warning: light-dark(#D97706, #FCD34D);
--color-danger: light-dark(#DC2626, #F87171);
--color-success-bg: light-dark(#F0FDF4, #052E16);
--color-warning-bg: light-dark(#FFFBEB, #2D1A00);
--color-danger-bg: light-dark(#FEF2F2, #2D0A0A);
}
Los componentes hacen referencia a estas variables sin necesitar saber nada sobre la tematización:
.card {
background: var(--color-bg-elevated);
border: 1px solid var(--color-border);
color: var(--color-text-primary);
}
.btn-primary {
background: var(--color-accent);
color: var(--color-text-inverse);
}
.btn-primary:hover {
background: var(--color-accent-hover);
}
.alert-success {
background: var(--color-success-bg);
color: var(--color-success);
border-left: 3px solid var(--color-success);
}
Observa que el acento claro #2563EB cambia a #60A5FA en modo oscuro. Esto es intencional — el azul de peso 600 pasa el contraste WCAG AA contra blanco pero falla contra fondos oscuros. El peso 400 aclara el color lo suficiente para mantener un contraste accesible en superficies oscuras. Usa el Verificador de Contraste para verificar que cada combinación cumpla con tu proporción de contraste objetivo, y el Generador de Sombras para encontrar la sombra correcta de cada color para cada modo.
Anidando light-dark() Dentro de Otras Funciones
light-dark() devuelve un valor de color, por lo que puede usarse en cualquier lugar donde un color sea válido — incluyendo dentro de otras funciones:
:root {
color-scheme: light dark;
--brand: #3B82F6;
/* Usa light-dark() dentro de color-mix() */
--brand-surface: color-mix(
in oklch,
var(--brand) 15%,
light-dark(white, #09090b)
);
}
Esto crea un color de superficie que es un tinte del 15% del color de marca, mezclado con blanco en modo claro y casi negro en modo oscuro — automáticamente consciente del tema.
Añadiendo un Interruptor de Usuario (JavaScript)
Responder a la preferencia del sistema es el valor predeterminado correcto, pero los usuarios deben poder anularlo. Esto requiere JavaScript para persistir su elección y anular el valor predeterminado del navegador.
Controlando color-scheme con JavaScript
La clave está en que color-scheme es una propiedad CSS que se puede establecer mediante JavaScript:
// Establecer el esquema de color programáticamente
document.documentElement.style.colorScheme = 'dark';
document.documentElement.style.colorScheme = 'light';
// Eliminar la sobrescritura (revierte a la preferencia del sistema)
document.documentElement.style.colorScheme = '';
Cuando estableces color-scheme mediante estilo en línea en el elemento raíz, sobreescribe la declaración de la hoja de estilos. Todos los valores light-dark() se resuelven nuevamente al variante apropiado.
Implementación Completa del Interruptor
const STORAGE_KEY = 'color-scheme-preference';
function initColorScheme() {
const stored = localStorage.getItem(STORAGE_KEY);
if (stored === 'light' || stored === 'dark') {
document.documentElement.style.colorScheme = stored;
}
// Si no hay preferencia guardada, el CSS color-scheme: light dark; lo maneja mediante la preferencia del SO
}
function toggleColorScheme() {
const current = getComputedStyle(document.documentElement)
.colorScheme
.trim();
// Determinar el siguiente valor
const next = current.includes('dark') ? 'light' : 'dark';
document.documentElement.style.colorScheme = next;
localStorage.setItem(STORAGE_KEY, next);
// Actualizar el estado del botón de alternancia
updateToggleButton(next);
}
function updateToggleButton(scheme) {
const btn = document.getElementById('theme-toggle');
if (!btn) return;
btn.setAttribute('aria-label',
scheme === 'dark' ? 'Cambiar a modo claro' : 'Cambiar a modo oscuro'
);
btn.dataset.scheme = scheme;
}
// Ejecutar antes del primer renderizado para evitar el destello
initColorScheme();
// Adjuntar al botón de alternancia después de que el DOM esté listo
document.addEventListener('DOMContentLoaded', () => {
document.getElementById('theme-toggle')
?.addEventListener('click', toggleColorScheme);
});
Llamar a initColorScheme() antes de que el DOM esté completamente analizado es fundamental. Si se ejecuta tarde, los usuarios con una preferencia guardada verán brevemente el tema predeterminado del SO antes de que cambie — el clásico "destello del tema incorrecto". Coloca este script en línea en <head> o usa el atributo defer con cuidado (ten en cuenta que los scripts defer se ejecutan después del análisis del DOM, lo que puede ser demasiado tarde).
El Patrón Anti-Destello
El enfoque más robusto contra el destello ejecuta un script en línea mínimo en <head>:
<head>
<meta name="color-scheme" content="light dark">
<script>
const stored = localStorage.getItem('color-scheme-preference');
if (stored) {
document.documentElement.style.colorScheme = stored;
}
</script>
<link rel="stylesheet" href="styles.css">
</head>
Este script se ejecuta de forma síncrona antes de que se aplique cualquier CSS, por lo que el navegador calcula el valor correcto de color-scheme desde el primer renderizado. La etiqueta <meta name="color-scheme"> le dice al navegador qué esquemas esperar incluso antes de que el CSS se analice — esto previene un breve destello blanco en páginas de modo oscuro en algunos navegadores.
Guía de Migración desde Temas Basados en JS
Muchas implementaciones existentes de modo oscuro usan un atributo data-theme alternado por JavaScript, con sobrescrituras CSS en el ámbito de [data-theme="dark"]. Migrar a light-dark() es incremental — no necesitas cambiar todo a la vez.
Paso 1: Añadir color-scheme a :root
:root {
color-scheme: light dark;
/* Las propiedades personalizadas existentes permanecen sin cambios */
}
Paso 2: Migrar Variables Una por Una
Empieza con una sola variable como prueba de concepto. Reemplaza el patrón de declaración dividida con un light-dark() unificado:
/* Antes */
:root {
--bg: #FFFFFF;
}
[data-theme="dark"] {
--bg: #0F0F17;
}
/* Después */
:root {
color-scheme: light dark;
--bg: light-dark(#FFFFFF, #0F0F17);
}
Paso 3: Actualizar el Interruptor
Cambia el interruptor de JavaScript de establecer data-theme a establecer style.colorScheme:
/* Antes */
document.documentElement.setAttribute('data-theme', scheme);
/* Después */
document.documentElement.style.colorScheme = scheme;
Paso 4: Eliminar los Selectores data-theme
Una vez que todas las variables estén migradas, elimina los bloques CSS [data-theme="dark"].
Mantener Ambos Durante la Transición
Puedes ejecutar ambos sistemas simultáneamente. Mantén las sobrescrituras [data-theme="dark"] para cualquier variable que aún no haya sido migrada. Las nuevas variables usan light-dark(). El interruptor de JavaScript establece tanto data-theme como style.colorScheme durante el período de transición.
Fallback de Soporte de Navegadores
Para el aproximado 15% de navegadores sin soporte de light-dark(), proporciona fallbacks explícitos:
:root {
/* Fallback: valores explícitos de modo claro */
--color-bg: #FFFFFF;
--color-text: #1A1A2E;
/* Mejora progresiva con light-dark() */
--color-bg: light-dark(#FFFFFF, #0F0F17);
--color-text: light-dark(#1A1A2E, #E8E8F0);
}
/* Modo oscuro de fallback para navegadores sin light-dark() */
@supports not (color: light-dark(white, black)) {
@media (prefers-color-scheme: dark) {
:root {
--color-bg: #0F0F17;
--color-text: #E8E8F0;
}
}
}
El bloque @supports not (color: light-dark(white, black)) solo se aplica a los navegadores que no entienden light-dark(). Los navegadores modernos lo omiten por completo porque la condición negativa es falsa.
Conclusiones Clave
light-dark(<light-value>, <dark-value>)devuelve el primer argumento en un esquema de color claro y el segundo en un esquema oscuro. Es la forma nativa de CSS de expresar "este color, adaptado para el tema actual."- Depende de que la propiedad CSS
color-schemeesté establecida en el elemento (o en un ancestro). Siempre establececolor-scheme: light darken:rootpara habilitar la adaptación automática medianteprefers-color-scheme. - La principal ventaja sobre el enfoque tradicional de media query es colocar ambos valores del tema en una sola declaración — haciendo explícita y auditable la relación entre las variantes claro y oscuro.
- Las sobrescrituras de usuario requieren establecer
document.documentElement.style.colorSchememediante JavaScript. Persiste la elección enlocalStoragey aplícala en un script en línea<head>antes de que se cargue el CSS para prevenir el destello. - La migración desde sistemas basados en atributo
data-themees incremental — mueve una variable a la vez del patrón de sobrescritura[data-theme="dark"]al patrón en línealight-dark(). - El soporte de navegadores es ~85% en 2026. Proporciona un fallback
@supports notcon un bloque@media (prefers-color-scheme: dark)para entornos más antiguos. - Usa el Verificador de Contraste para verificar que tanto los valores de color claro como oscuro en cada par
light-dark()pasen los requisitos de contraste WCAG frente a sus respectivos fondos, y el Generador de Sombras para encontrar la sombra correcta de cada color para cada modo.
Colores relacionados
Marcas relacionadas
Herramientas relacionadas
Verificador de contraste
Verifica las relaciones de contraste de color según las directrices WCAG 2.1. Prueba el cumplimiento AA y AAA para texto normal y grande.
Generador de tonos
Genera escalas de tonos estilo Tailwind CSS (50–950) a partir de cualquier color base para sistemas de diseño.