Этот пост посвящен Astro, фреймворку, с помощью которого вы создаете более быстрые веб-сайты с меньшим количеством клиентского JavaScript.

Использование темного режима стало популярным. Многие крупные веб-сайты и приложения разрабатывают свои собственные версии, которые часто выполняются с использованием переменных CSS.

В этом посте мы рассмотрим, как добавить поддержку темного режима на ваш сайт двумя способами: сначала с помощью CSS, а затем с помощью переключателя JavaScript.

Предпосылки

Я настоятельно рекомендую вам сделать форк Astro starter от Astro.new.

Вы можете выбрать шаблон по вашему выбору, а затем открыть шаблон в CodeSandbox, который автоматически обработает необходимые зависимости.

Создание нашего компонента Dark Mode

В папку компонентов я добавил новый компонент под названием ThemeChange.astro. Его базовая функциональность включает в себя кликабельный элемент рядом с нашими изображениями svg для нашего переключателя.

<div class="theme-switch-wrapper">
          <label class="theme-switch" for="checkbox">
            <input type="checkbox" id="checkbox" />
            <div class="slider">
              <svg
                xmlns="http://www.w3.org/2000/svg"
                width="16"
                height="16"
                viewBox="0 0 24 24"
                fill="#FCD53F"
                stroke="currentColor"
                stroke-width="2"
                stroke-linecap="round"
                stroke-linejoin="round"
                class="feather feather-sun"
              >
                <circle cx="12" cy="12" r="5"></circle>
                <line x1="12" y1="1" x2="12" y2="3"></line>
                <line x1="12" y1="21" x2="12" y2="23"></line>
                <line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
                <line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
                <line x1="1" y1="12" x2="3" y2="12"></line>
                <line x1="21" y1="12" x2="23" y2="12"></line>
                <line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
                <line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
              </svg>
              <svg
                xmlns="http://www.w3.org/2000/svg"
                width="16"
                height="16"
                viewBox="0 0 24 24"
                fill="#FCD53F"
                stroke="currentColor"
                stroke-width="2"
                stroke-linecap="round"
                stroke-linejoin="round"
                class="feather feather-moon"
              >
                <path
                  d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"
                ></path>
              </svg>
            </div>
          </label>
        </div>

Мы сразу же импортируем этот компонент в компонент Header.

---
import HeaderLink from './HeaderLink.astro';
import { SITE_TITLE } from '../config';
import Toggle from './ThemeChange.astro';
---

<header>
    <Toggle />
    <h2>
        {SITE_TITLE}
    </h2>
    <nav>
        <HeaderLink href="/">Home</HeaderLink>
        <HeaderLink href="/blog">Blog</HeaderLink>
        <HeaderLink href="/about">About</HeaderLink>
        <HeaderLink href="https://twitter.com/astrodotbuild" target="_blank">Twitter</HeaderLink>
        <HeaderLink href="https://github.com/withastro/astro" target="_blank">GitHub</HeaderLink>
    </nav>
</header>
<style>
    header {
        margin: 0em 0 2em;
    }
    h2 {
        margin: 0.5em 0;
    }
</style>

Использование переменных CSS для тем

Переменные CSS позволяют нам определять многократно используемые значения, которые можно изменить во время выполнения. Во-первых, в корневом элементе определите все доступные цвета. Затем, используя эти цвета, создайте две противоположные темы данных: светлую и темную.

:root {
  --color-bg: #f2f2f2;
  --color-text: #444444;
  --bold-text: #222;
  --nav-text: #000000;
  --code: #f2f2f2;
  --block-quote-border: #999;
  --block-quote-text: #222;
  --slider-bg: #dddddd;
  --slider-bg-before: #fff;
  --slider-input-bg: #8758ff;
}

[data-theme="light"] {
  --color-bg: #f2f2f2;
  --color-text: #444444;
  --bold-text: #222;
  --nav-text: #000000;
  --code: #f2f2f2;
  --block-quote-border: #999;
  --block-quote-text: #222;
  --slider-bg: #dddddd;
  --slider-bg-before: #fff;
  --slider-input-bg: #8758ff;
}

[data-theme="dark"] {
  --color-bg: #000;
  --color-text: #dddddd;
  --bold-text: #eeeeee;
  --nav-text: #dddddd;
  --code: #f2f2f2;
  --block-quote-border: #8e32dc;
  --block-quote-text: #dddddd;
}

💡 Примечание. Когда data-theme="dark" применяется к элементу ‹body›, background-color элемента >компонент меняется с белого на черный.

Примените ту же концепцию ко всем цветам в своем веб-приложении, и вы получите переключатель тем! Чего не хватает, так это переключаемого элемента, который при включении добавляет или удаляет тему данных из элемента body.

Наконец, мы применим остальные стили нашего переключателя, как показано ниже.

/* TOGGLE  */
.theme-switch-wrapper {
  display: flex;
  justify-content: flex-end;
  align-items: center;
}

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

.theme-switch input {
  display: none;
}

.slider {
  background-color: var(--slider-bg);
  bottom: 0;
  cursor: pointer;
  left: 0;
  position: absolute;
  right: 0;
  top: 0;
  transition: 0.4s;
  border-radius: 34px;
}

.slider:before {
  background-color: var(--slider-bg-before);
  bottom: 4px;
  content: "";
  height: 26px;
  left: 4px;
  position: absolute;
  transition: 0.4s;
  width: 26px;
  border-radius: 50%;
}

input:checked + .slider {
  background-color: var(--slider-input-bg);
}

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

.slider svg {
  color: #222;
  position: absolute;
  transition: opacity 0.2s ease 0s, transform 0.35s ease 0s;
  pointer-events: none;
}

.feather-moon {
  opacity: 0;
  left: 9px;
  bottom: 9px;
  transform: translateX(4px);
}

.feather-sun {
  opacity: 1;
  right: 10px;
  bottom: 9px;
  transform: translateX(0px);
}

input:checked + .slider .feather-moon {
  opacity: 1;
  transform: translateX(0);
}

input:checked + .slider .feather-sun {
  opacity: 0;
  transform: translateX(-4px);
}

💡 Примечание. Если вы застряли с выбором цветов для своих переменных CSS, откройте для себя новейшие подобранные вручную палитры из Color Hunt.

JavaScript

В JavaScript локальное хранилище — это объект, который является частью объекта окна, поэтому мы можем получить к нему прямой доступ и попытаться найти элемент, хранящийся внутри. Мы используем функцию getItem и передаем свойство, которое хотим найти, внутри нашего компонента ThemeChange.Astro.

<script>
          // Get the theme toggle input
          const themeToggle = document.querySelector(
            '.theme-switch input[type="checkbox"]'
          );

          // Get the current theme from local storage
          const currentTheme = localStorage.getItem("theme");

          // If the current local storage item can be found
          if (currentTheme) {
            // Set the body data-theme attribute to match the local storage item
            document.documentElement.setAttribute("data-theme", currentTheme);

            // If the current theme is dark, check the theme toggle
            if (currentTheme === "dark") {
              themeToggle.checked = true;
            }
          }

          // Function that will switch the theme based on the if the theme toggle is checked or not
          function switchTheme(e) {
            if (e.target.checked) {
              document.documentElement.setAttribute("data-theme", "dark");
              localStorage.setItem("theme", "dark");
            } else {
              document.documentElement.setAttribute("data-theme", "light");
              localStorage.setItem("theme", "light");
            }
          }

          // Add an event listener to the theme toggle, which will switch the theme
          themeToggle.addEventListener("change", switchTheme, false);

</script>

Вот окончательный результат, когда все компоненты на месте:

Заключение

Спасибо за чтение, и давайте подключаться!

Не стесняйтесь подписываться на мою электронную рассылку и подключаться к Twitter.