Estoy tratando de alternar entre un ícono de luna y un ícono de sol en un proyecto de modo oscuro. El código javascript original era simplemente un botón que cambiaba del modo diurno al modo oscuro. Después de investigar un poco, terminé con el siguiente código, que "algo" funciona pero es incompleto; cambia del modo diurno al modo oscuro y el icono cambia de luna a sol PERO, cuando vuelvo a la página después de configurar mi preferencia como modo oscuro (o actualizar la página en modo oscuro), el icono desaparece.
const btn = document.querySelector(".btn-mode"); const icon = document.querySelector(".mode"); const prefersDarkScheme = window.matchMedia("(prefers-color-scheme: dark)"); const currentTheme = localStorage.getItem("theme"); if (currentTheme == "dark") { document.body.classList.toggle("dark-theme"); icon.classList.toggle("fa-sun-o"); } else if (currentTheme == "light") { document.body.classList.toggle("light-theme"); icon.classList.toggle("fa-moon-o"); } btn.addEventListener("click", function () { if (prefersDarkScheme.matches) { document.body.classList.toggle("light-theme"); var theme = document.body.classList.contains("light-theme") ? "light" : "dark"; icon.classList.toggle("fa-sun-o"); } else { document.body.classList.toggle("dark-theme"); var theme = document.body.classList.contains("dark-theme") ? "dark" : "light"; icon.classList.toggle("fa-moon-o"); } localStorage.setItem("theme", theme); });¿Alguna idea de lo que me estoy perdiendo aquí?
Creé un codepen para mostrar el problema.
Como han dicho otros, estaba usando un método de toggle que producía un comportamiento inconsistente.
Refactoricé un poco el código:
const btn = document.querySelector(".btn-mode"); const icon = document.querySelector(".mode"); const prefersDarkScheme = window.matchMedia("(prefers-color-scheme: dark)"); const makeDark = () => { document.body.classList.add("dark-theme"); document.body.classList.remove("light-theme"); icon.classList.add("fa-moon-o"); icon.classList.remove("fa-sun-o"); } const makeLight = () => { document.body.classList.remove("dark-theme"); document.body.classList.add("light-theme"); icon.classList.remove("fa-moon-o"); icon.classList.add("fa-sun-o"); } const setPageThemeTo = (newLightDarkState) => { newLightDarkState == "dark" ? makeDark() : makeLight(); } let currentTheme = localStorage.getItem("theme"); if (!currentTheme) { currentTheme = prefersDarkScheme.matches ? 'dark' : 'light'; } setPageThemeTo(currentTheme); btn.addEventListener("click", function () { currentTheme = currentTheme == "dark" ? "light" : "dark"; localStorage.setItem("theme", currentTheme); setPageThemeTo(currentTheme); });¡Probablemente podrías SECARLO aún más! :)
Debe alternar ambas clases cada vez que desee hacer un cambio.
Su código estaba usando el método de alternar como si cambiara la luna por el sol, pero en realidad solo cambia si la clase individual está allí. Cambié ambas clases cuando necesitamos hacer un cambio, y comenté las cosas del almacenamiento local para evitar errores de JS con el fragmento SO, pero por lo demás no cambié su código.
const btn = document.querySelector(".btn-mode"); const icon = document.querySelector(".mode"); const prefersDarkScheme = window.matchMedia("(prefers-color-scheme: dark)"); // const currentTheme = localStorage.getItem("theme"); // if (currentTheme == "dark") { // document.body.classList.toggle("dark-theme"); // icon.classList.toggle("fa-moon-o"); // } btn.addEventListener("click", function() { if (prefersDarkScheme.matches) { document.body.classList.toggle("light-theme"); var theme = document.body.classList.contains("light-theme") ? "light" : "dark"; } else { document.body.classList.toggle("dark-theme"); var theme = document.body.classList.contains("dark-theme") ? "dark" : "light"; } icon.classList.toggle("fa-moon-o"); icon.classList.toggle("fa-sun-o"); // localStorage.setItem("theme", theme); }); body { --text-color: #555; --bkg-color: #fff; } body.dark-theme { --text-color: #999; --bkg-color: #222; } body { background: var(--bkg-color, #fff); color: var(--text-color, #555); } .btn-mode { background: #000; font-size: 20px; padding: 10px 10px; width: 50px; cursor: pointer; color: #fff; display: block; text-align: center; } .btn-mode:hover { color: #da0000; } <html> <head> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"> </head> <body class="light-theme"> <h1>Some title</h1> <ul> <li class="btn-mode"> <i class="mode fa fa-sun-o"></i> </li> </ul> </body </html>