9 Sty 2020

Ciemny/Jasny motyw na stronie

Coraz więcej programów ale również i stron posiada motyw ciemny. Nie będę tutaj się zajmował tym czy i dlaczego używać ciemnego motywu. Takie informacje Sami jesteście wstanie znaleźć w internecie.
Dla mnie ciemny motyw jest idealny do pracy, mniej męczy oczy, jest też część techniczna bo ciemny motyw na urządzeniach OLED czy AMOLED nie zużywa energii itd.
Tak naprawdę to nie jest istotne czy strona jest jasna czy ciemna ale to jaki jest kontrast między elementami tło/tekst.

Przejdźmy do konkretów. Strona będzie posiadała przełącznik między ciemnym/jasnym motywem. Dane będą zapisywane w localStorage, a to po to aby po odświeżeniu strony nasz wybór nadal był aktualny. Oczywiście nic nie stoi na przeszkodzie aby gdzie indziej zapisywać te informacje.

Nie chcemy aby po wybraniu ciemnego motywu i po przejściu na inną stronę motyw z powrotem zmienił się na jasny. Domyślnie strona jest w motywie jasnym, dopiero kliknięcie na przełącznik zmienia nam motyw.

Najpierw porcja prostego html. Zaczniemy od przełącznika.

<nav>
  <div class="theme-switch-wrapper">
    <label class="theme-switch" for="checkbox">
      <input type="checkbox" id="checkbox" />
      <div class="slider round"></div>
    </label>
  </div>
</nav>

Zaś css oraz miejsce jego umieszczenie prezentuje poniższy css:

nav {
  display: flex;
  justify-content: flex-end;
  padding: 20px 0;
}

.theme-switch {
  display: inline-block;
  height: 34px;
  position: relative;
  width: 60px;
}

.theme-switch input {
  display: none;
}

.theme-switch-wrapper {
  display: flex;
  align-items: center;
}

.theme-switch-wrapper em {
  margin-left: 10px;
  font-size: 1rem;
}

.slider {
  background-color: #ccc;
  bottom: 0;
  cursor: pointer;
  left: 0;
  position: absolute;
  right: 0;
  top: 0;
  transition: 0.4s;
}

.slider:before {
  background-color: #fff;
  bottom: 4px;
  content: "";
  height: 26px;
  left: 4px;
  position: absolute;
  transition: 0.4s;
  width: 26px;
}

.slider.round {
  border-radius: 34px;
}

.slider.round:before {
  border-radius: 50%;
}

input:checked + .slider {
  background-color: #66bb6a;
}

input:checked + .slider:before {
  transform: translateX(26px);
}

Nasze style oprzemy o zmienne var.

:root {
  --primary-color: #24242b;
  --secondary-color: #433055;
  --font-color: #3f3f3f;
  --bg-color: #f3f3f3;
  --heading-color: #2a2a23;
}

html[data-theme="dark"] {
  --primary-color: #f89898;
  --secondary-color: #8894b3;
  --font-color: #d8d8f6;
  --bg-color: #242424;
  --heading-color: #818cab;
}

Pierwsze część czyli :root jest to styl wersji jasnej.
Druga cześć html[data-theme=”dark”] odpowiada za wersję ciemną. data-theme=”dark” jest dodawane to html za pomocą javascript po kliknięciu w przełącznik.

Reszta stylii odpowiedzialna za to jak będą zmieniać się kolory, background, kolor czcionki, h1, itd:

body {
  font-family: "Lato", sans-serif;
  background-color: var(--bg-color);
  color: var(--font-color);
  max-width: 900px;
  margin: 0 auto;
  padding: 0 30px;
  font-size: calc(1rem + 0.25vh);
}

h1 {
  color: var(--heading-color);
  font-family: "Lato", serif;
  font-size: 3rem;
  margin-bottom: 1vh;
}

p {
  font-size: 1.1rem;
  line-height: 1.6rem;
}

a {
  color: var(--primary-color);
  text-decoration: none;
  border-bottom: 3px solid transparent;
  padding-bottom: 5px;
  transition: border-bottom 1s;
  font-weight: bold;
}
a:hover,
a:focus {
  border-bottom: 3px solid currentColor;
}

section {
  margin: 0 auto;
}

.post-meta {
  font-size: 1rem;
  font-style: italic;
  display: block;
  margin-bottom: 4vh;
  color: var(--secondary-color);
}

Teraz przyszedł czas na javascript, jest on bardzo prosty.

const toggleSwitch = document.querySelector('.theme-switch input[type="checkbox"]');
// pobieramy z localStorage theme rodzaj dark/light
const currentTheme = localStorage.getItem('theme');

// jeżeli theme istnieje 
if (currentTheme) {
  // ustawiamy data-theme klasę w elemencie html data-theme="light"
  document.documentElement.setAttribute('data-theme', currentTheme);

  // jeżeli theme jest dark zmieniamy przełącznik a dokładnie checkbox na true
  if (currentTheme === 'dark') {
    toggleSwitch.checked = true;
  }
}

// funkcja ustawiająca data-theme w zależności od przełącznika
function switchTheme(event) {
  if (event.target.checked) {
    document.documentElement.setAttribute('data-theme', 'dark');
    localStorage.setItem('theme', 'dark');
  }
  else {
    document.documentElement.setAttribute('data-theme', 'light');
    localStorage.setItem('theme', 'light');
  }
}

// obserwujemy zdarzenie w naszym przypadku na change uruchamiamy funkcję switchTheme
toggleSwitch.addEventListener('change', switchTheme, false);

To chyba tyle, poniżej cały działający przykład.

See the Pen
Dark / Light theme on the page
by Greg (@Tomik23)
on CodePen.