Nuxt.js app от UI-кита до деплоя. Часть 2: Темная тема
Публикуем вторую часть серии статей о создании современного блога на Nuxt.js. Сегодня реализуем темную тему в приложении, которое мы написали вместе с вами в первой части.
Обратите внимание, что код каждой части можно найти в собственной ветке на Github, а в master доступна версия приложения из последней опубликованной статьи.

Что такое темная тема?
Темная тема — это цветовая схема любого интерфейса, которая отображает светлый текст и элементы интерфейса на темном фоне, что упрощает просмотр экрана на мобильных телефонах, планшетах и компьютерах при плохой освещенности. Темная тема уменьшает свет, излучаемый экраном, при сохранении минимального соотношения цветового контраста, необходимого для удобочитаемости.
Темная тема улучшает визуальную эргономику, снижая нагрузку на глаза, настраивая экран в соответствии с текущими условиями освещения и обеспечивая простоту использования в ночное время или в темноте.
Также нельзя забывать о том, что использование темной темы в веб- и мобильных приложениях может продлить срок службы батареи устройства. Компания Google подтвердила, что темная тема на OLED экранах очень помогает продлить срок службы батареи.
@nuxtjs/color-mode
Для реализации темной темы мы будем использовать модуль @nuxtjs/color-mode, который предоставляет следующие возможности:
- добавляет класс
.${color}-modeк тегудля упрощения управлением темами CSS; - работает в любом режиме
Nuxt(static,ssrилиspa); - автоматически определяет цветовой режим системы на устройстве пользователя и может установить соответствующую тему, исходя из этих данных;
- позволяет синхронизировать выбранную тему между вкладками и окнами;
- позволяет использовать реализованные темы для отдельных страниц, а не для всего приложения (идеально подходит для постепенной разработки);
- также модуль поддерживает IE9+ (не уверен, что это всё еще актуально в современной разработке, но кому-то может пригодиться).
Для начала установим модуль:
npm i --save-dev @nuxtjs/color-modeА затем добавим добавим информацию об этом модуле в секцию
buildModules в файле nuxt.config.js: {
buildModules: [
'@nuxtjs/color-mode'
]
}Отлично! Теперь, если мы запустим наше приложение и откроем вкладку
Elements в консоли разработчика, то увидим, что к тегу html добавился класс, который соответствует теме операционный системы, например, в нашем случае class="light-mode".Переключатель темы
На следующем этапе давайте реализуем переключатель, который будет менять темную тему на светлую и наоборот.
Если посмотреть на дизайн нашего приложения в Figma, то мы увидим, что рядом с переключателем темы также находится переключатель языка, который мы реализуем в одной из следующих статей этого цикла.
Сразу напишем компонент-обертку, который будет инкапсулировать эти переключатели и отвечать за внешние отступы до других компонентов.
Для этого создадим компонент AppOptions со следующим содержимым:
section.section
.content
.app-options
switcher-color-mode
Компонент на Github.
Как мы видим, в этом компоненте нет никакой логики, он просто устанавливает внешние отступы для вложенных компонентов. Сейчас у нас только один вложенный компонент switcher-color-mode, реализуем его.
Взглянем на секцию script этого компонента:
Здесь мы реализуем метод
changeColorMode, который меняет тему в объекте, предоставляемом модулем @nuxtjs/color-mode.При изменении значения $colorMode.preference также будет установлен соответствующий класс у тега html: class="light-mode" или class="dark-mode".
Кроме того, здесь есть вычисляемое свойство icon, которое возвращает нужную нам иконку в зависимости от выбранной темы. Обратите внимание, что для корректной работы нужно добавить иконки sun.svg и moon.svg в директорию assets/icons.
Шаблон компонента будет выглядеть следующим образом:
button(@click="changeColorMode")
img(
alt="theme-icon"
:src="getDynamicFile(icon)"
)
Здесь всё совсем просто! У нас есть кнопка, при клике на которую мы вызываем метод
changeColorMode и меняем нашу тему. Внутри кнопки мы показываем изображение выбранной темы.Компонент на Github.
Остается только добавить этот компонент на главную страницу нашего приложения. После этого шаблон страницы должен выглядеть так:
.page
section-header(
title="Nuxt blog"
subtitle="The best blog you can find on the global internet"
)
app-options
post-list
Управление переменными
Как вы, возможно, помните из первой части, для определения всех цветов в приложении мы использовали
scss переменные, и теперь всё, что нам остаётся сделать, это изменять значения этих переменных в зависимости от выбранной темы.Но проблема в том, что scss переменные задаются один раз при сборке приложения и в дальнейшем мы не можем переопределять их при изменении темы.
Это ограничение можно обойти с помощью js, но есть решение намного проще: мы можем использовать нативные css переменные.
Сейчас в нашем файле с переменными assets/styles/variables.scss секция с цветами выглядит следующим образом:
// colors
$text-primary: rgb(22, 22, 23);
$text-secondary: rgb(110, 109, 122);
$line-color: rgb(231, 231, 233);
$background-color: rgb(243, 243, 244);
$html-background-color: rgb(255, 255, 255);Давайте для начала в этом же файле определим две цветовые схемы — светлую и темную — с помощью
css переменных: :root {
// light theme
--text-primary: rgb(22, 22, 23);
--text-secondary: rgb(110, 109, 122);
--line-color: rgb(231, 231, 233);
--background-color: rgb(243, 243, 244);
--html-background-color: rgb(255, 255, 255);
// dark theme
&.dark-mode {
--text-primary: rgb(250, 250, 250);
--text-secondary: rgb(188, 187, 201);
--line-color: rgb(45, 55, 72);
--background-color: rgb(45, 55, 72);
--html-background-color: rgb(26, 32, 44);
}
}Мы определили
css переменные в селекторе :root. По стандарту css переменная задается и используется с помощью префикса --.О css псевдоклассе :root можно прочесть на MDN и W3Schools. Цитата с MDN:
css псевдокласс :root находит корневой элемент дерева документа. Применимо к HTML, :root находит тег html и идентичен селектору по тегу html, но его специфичность выше.
Как мы видим, те цвета, которые раньше были прописаны напрямую в scss переменные, сейчас указаны в css переменных как значения по умолчанию, а при наличии класса .dark-mode эти значения переопределяются.
Теперь наши scss переменные с цветами будут выглядеть следующим образом:
$text-primary: var(--text-primary);
$text-secondary: var(--text-secondary);
$line-color: var(--line-color);
$background-color: var(--background-color);
$html-background-color: var(--html-background-color);При переключении темы цветовая схема будет меняться в соответствии с заданными значениями и нам не нужно ничего менять в уже реализованных компонентах.
Заключение
Благодаря этой статье мы научились реализовывать темную тему для приложения на Nuxt.js.
Удалось выполнить все шаги? Как вы думаете, темная тема — это просто хайп или все-таки необходимость? Делитесь мыслями в комментариях.
Ссылки на необходимые материалы:
