Tengo:
body { background: white; } Para mostrar el modo oscuro, uso .dark class:
.dark body { background: black; }Y para detectar si el usuario tiene su sistema operativo configurado para usar un tema oscuro, tenemos un esquema de color preferido :
@media (prefers-color-scheme: dark) { body { background: black; } }Y luego tenemos la idea de la programación DRY (Don't Repeat Yourself). ¿Podemos definir el modo oscuro sin repetir las declaraciones de propiedades CSS y, en el proceso , permitir que los usuarios cambien entre los modos de color a través de JS?
Con el ejemplo anterior, la clase .dark y la consulta de medios son copias entre sí.
Se omitió prefers-color-scheme en CSS y se usó:
body { background: white; } .dark body { background: black; }Luego, a través de JS, detecte su configuración y ajuste el
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) { document.getElementsByTagName('html')[0].classList.add('dark'); } El problema con este enfoque es que no usa prefers-color-scheme en CSS.
Si bien puedo agregar:
@media (prefers-color-scheme: dark) { body { background: black; } } No me permite alternar los esquemas de color a través de JS porque no puedo cancelar prefers-color-scheme: dark para un usuario que tiene un ajuste oscuro en sus preferencias de sistema operativo.
¿Cuál es la forma 2022 de resolver esto?
Puede aprovechar la consulta de medios de CSS sin usarla realmente en el CSS mediante el uso de JS.
Por ejemplo, tomando su clase .dark de su código, podría usar un objeto MediaQueryList :
const darkMode = window.matchMedia("(prefers-color-scheme: dark)");Y configure un conmutador para la lista de clases del documento:
// Initial setting document.documentElement.classList.toggle("dark", darkMode.matches); // Listener to changes darkMode.addListener((event) => document.documentElement.classList.toggle("dark", event.matches)); De esa manera, puede concentrarse en sus archivos CSS en solo definir las clases bajo la clase .dark y no necesitará definirla dos veces usando la consulta de medios. Además, al hacerlo de esa manera, puede configurar la configuración para el usuario que anularía la preferencia predeterminada del sistema operativo en caso de que lo desee (por ejemplo, guardarlo en una localStore , etc.)
Si desea hacer esto con css , puede probar el siguiente método
:root { --body-background-color: white; } @media (prefers-color-scheme: dark) { :root { --body-background-color: black; } } body { background-color: var(--body-background-color); }Podrías lograr eso invirtiendo la lógica.
body { background: black; } @media (prefers-color-scheme: light) { :root:not(.dark) body { background: white; } }A continuación se muestra una solución simple que usa variables CSS , consulta de medios prefers-color-scheme preferido y botones de opción. Aquí, la página detecta el tema oscuro/claro del sistema operativo y permite al usuario cambiar el tema haciendo clic en los botones de opción sin JavaScript. También puede activar un evento de clic en estos botones de opción si realmente necesita JavaScript.
/* Defines theme variables */ :root { --theme-light-color: #222222; --theme-light-background: #FFFFFF; --theme-dark-color: #DDDDDD; --theme-dark-background: #222222; } /* Defines body content styles */ body { margin: 0; } body>main { min-height: 100vh; color: var(--theme-main-color); background: var(--theme-main-background); } label[for="theme-light"] { color: var(--theme-light-color); background: var(--theme-light-background); cursor: pointer; } label[for="theme-dark"] { color: var(--theme-dark-color); background: var(--theme-dark-background); cursor: pointer; } /* IF theme = light THEN */ #theme-light:checked~main { --theme-main-color: var(--theme-light-color); --theme-main-background: var(--theme-light-background); } @media (prefers-color-scheme: light){ :root { --theme-main-color: var(--theme-light-color); --theme-main-background: var(--theme-light-background); } } /* IF theme = dark THEN */ #theme-dark:checked~main { --theme-main-color: var(--theme-dark-color); --theme-main-background: var(--theme-dark-background); } @media (prefers-color-scheme: dark){ :root { --theme-main-color: var(--theme-dark-color); --theme-main-background: var(--theme-dark-background); } } <!DOCTYPE html> <html lang="en"> <body> <!-- THEME SWITCH --> <input type="radio" id="theme-light" name="theme" hidden> <input type="radio" id="theme-dark" name="theme" hidden> <!-- BODY CONTENT --> <main> <label for="theme-light">Light</label> <label for="theme-dark">Dark</label> <p>Hello World!</p> </main> </body> </html>