Przełącznik motywu, tryb nocny na blogu/stronie

Tryb ciemny/jasny w łatwy sposób, tylko JS.


Zawszę doceniam, gdy na stronach/blogach mamy możliwość zmiany motywu na ciemny. Jest to świetna opcja do czytania lub do przeglądania strony bez światła. Dlatego też zaimplementowałem taką funkcję na swoim blogu (w prawym górnym rogu w navbarze).

Pokażę jak to wykonałem - relatywnie szybko i bezboleśnie, na przykładzie tego bloga :slightly_smiling_face:

Przygotowywujemy przycisk

To kwestia gustu. Tutaj jest w navbarze - na liście opcji, z tooltipem i ikonami fontawsome:

<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
 <ul class="nav navbar-nav navbar-right">
  <!--  ...  -->
  <li>
    <button class="dark-mode-btn nav-el" data-toggle="tooltip" data-placement="bottom" title="Zmień motyw">
     <i class="fa fa-sun-o" aria-hidden="true"></i>/<i class="fa fa-moon-o" aria-hidden="true"></i>
    </button>
  </li>
 </ul>
</div>

Obsługujemy zmianę i zapamiętujemy wybór w LocalStorage

Zaimplementowałem to w ten sposób, że po kliknięciu przycisku przełączany jest motyw (u mnie dodawana jest klasa “dark-mode” do body) oraz zapamiętywany jest nasz wybór w localStorage - czyli w pamięci cache przeglądarki dopóki jej nie wyczyścimy.

Dałoby się to zrobić za pomocą ciasteczek, ale wykorzystanie localStorage jest bardziej odpowiednie, gdyż nie wysyłamy nic w nagłówku HTTP (nie marnujemy łącza :smile:) i nie wygaśnie nam to po jakimś czasie. Wszystkie dzieje się w przeglądarce użytkownika. Poza tym, ciasteczka są przeznaczone do odczytywania po stronie serwera.

Tak więc dodajemy obsługę kliknięcia:

document.querySelector('.dark-mode-btn').addEventListener('click', (e) => {
  const darkMode = document.body.classList.toggle('dark-mode');
  e.target.blur();
  localStorage.setItem('dark-mode', darkMode);
});

e.target.blur(); odznacza przycisk po kliknięciu, bez tego byłby aktywny.

Poza tym, przy otwieraniu strony powinien zostać wczytany zapamiętany wybór i zmieniony motyw jeśli jest taka potrzeba:

if (JSON.parse(localStorage.getItem('dark-mode'))) {
  document.body.classList.add('dark-mode');
}

U mnie klasa CSS zmieniającą motyw jest aż tak prosta:

.dark-mode {
  background: #2a2a2a;
  color: #e2e2e2;
}

Wiadomo, jęśli masz więcej elementów, którym będziesz chciał zmienić wygląd po przełączeniu motywu, tym więcej modyfikacji CSS będziesz musiał dokonać. Jeśli chcesz, żeby inne elementy też zmieniały swój wygląd, to będziesz musiał stworzyć selector w CSS, który dziedziczy po .dark-mode, czyli np. jeśli masz element div z klasą “whatever”, jego wersję dla ciemnego motywu zdefiniujesz tak:

.dark-mode .whatever {
    key: property;
    key: property;
    key: property;
}

W rezultacie te wartości będą się załączać tylko wtedy, kiedy body będzie miało klasę:

<code class="highlight"><span class="na">.dark-mode</span></code>

Dostosowywanie strony do zmian

Pozostało nam dostosować bloga/stronę do takiej zmiany i w niektórych elementach CSS pozmieniać wartości background i color na inherit, aby kolory były dziedziczone z klasy .dark-mode. Poza tym, prawdopodobnie czeka nas kilka zmian kolorystycznych, aby dopasować się do dwóch trybów.

Zdaję sobię, że nie u każdego będzie to takie banalne i czasem wasza strona może wymagać głębszej modyfikacji css, aby nasza strona wyglądała dobrze po zmianie motywu. Dlatego dobrze jest dobierać kolory, które wyglądają ładnie w obu motywach. Wtedy pójdzie to tak szybko jak u mnie :wink:

Jeśli używasz Disqus na swojej stronie, to przy zmianie motywu sekcja komentarzy może nie wyglądać poprawnie. Jeśli masz zaznaczoną opcję, aby disqus dostosowywał wygląd automatycznie, możesz wymusić jego przeładowanie po zmianie motywu, aby ponownie się dopasowałAC. Wystarczy dodać taką linijkę tam gdzie obsługujemy kliknięcie:

try {
    DISQUS.reset({ reload: true });
} catch (e) {}

Jest to w try catch, ponieważ zakładam, że nie na każdej stronie masz sekcję komentarzy :slightly_smiling_face:


Jeśli uważasz, że to co robię jest przydatne, polub stronę bloga na Facebooku. Wrzucam tam m.in. informacje o nowych wpisach, o promocjach dla programistów i inne.