Русский
Русский
English
Статистика
Реклама

Dark mode

Темизация. История, причины, реализация

18.06.2021 22:18:25 | Автор: admin

Введение. Причины появления

Когда веб только зарождался единственной его целью было размещение контента (гипертекстовые страницы), чтобы у пользователей из всемирной паутины был к нему доступ. В то время не могло идти и речи о дизайне, ведь зачем нужен дизайн страницам с научными публикациями, разве они станут от этого полезнее (первый сайт). Времена меняются и сегодня во всемирной паутине далеко не только научные публикации. Блоги, сервисы, социальные сети и многое, многое другое. Каждый сайт нуждается в своей индивидуальности, ему необходимо заинтересовывать и привлекать пользователей. Даже научные сайты постепенно это понимают, ведь большинство ученых хотят не просто изучать те или иные аспекты, а доносить их до людей, тем самым повышая свою популярность и ценность своих исследований (пример 15 из 15 научных сайтов списка сделали редизайн в последние 6 лет). Рядовым обывателям не интересен серый сайт с непонятным содержанием. Наука становится доступнее, а сайты преобразуются в приложения с удобным и приятным интерфейсом.

Так как "удобство" у каждого свое нет четкого определения и конкретных правил по реализации удобного для всех сервиса. В последние годы к этому понятию стали привязывать такое понятие, как Темизация. Именно о нем я и хочу рассказать в данной статье.

Думаю, это крайне полезное улучшение. Его появление было неизбежным и, даже странно, что оно стало популярным так поздно. И бизнес, и разработчики делают свои продукты так, чтобы они были доступны всем, везде и всегда. Поэтому, например, в современных оболочках появились функции оттенки желтого и оттенки синего. Тем не менее, не всех устраивают эти функции, поэтому сервисы тоже думают об удобстве использования и здоровье своих любимых пользователей.

Темная тема для ночного периода это не единственная причина добавления темизации на сайт. Другой важной задачей стоит доступность сервиса. Во все мире 285 млн людей с полной или частичной потерей зрения, в России 218т [ист.], до 2,2 млрд с различными дефектами [ист.] почти треть детей в России заканчивает школу в очках[ист.]. Статистика поражает воображение. Однако, большинство людей не лишено зрения полностью, а имеют лишь небольшие отклонения. Это могут быть цветовые отклонения или качественные. Если для качественных отклонений доступность достигается за счет добавления поддержки разных размеров шрифтов, то для цветовых отличным решением является именно добавление темы.

История развития. Бесконечный путь

Каждый сайт соответствует определенной цветовой гамме. В первую очередь, это понятие связывается с темной темой и именно с нее стоит начать. В прежние времена, когда цветовая гамма сводилась к оттенкам черного и белого, для реализации темной темы нужно было просто сделать инверсию этих оттенков. Как жаль, что о подобных вещах задумываются не в тот момент, когда их легко реализовать, а когда их реализация является отдельным испытанием. Сейчас же, с углублением связей с дизайном и ростом запросов пользователей цветовая гамма каждого сайта становится уникальной, порою неожиданной и впечатляющей воображение. Дизайнеры в этом плане способны творить чудеса, сочетая несочетаемое. К сожалению, подобные дизайны сочетаемы только в текущей расцветке и инвертировав их оттенки получится совершенно ужасный дизайн. Поэтому, проектируя современные проекты, в которых планируется несколько тем заранее создаются цветовые гаммы светлая, темная, розовая и т.д. В дальнейшем, при разработке дизайна все оттенки берутся уже из этой гаммы.

Дизайн только одна из составляющих каждого сайта. Во время разработки сайт проходит через множество людей разработчиков, аналитиков, тестировщиков, маркетологов. Темизация так или иначе затрагивает каждого из них. И, в первую очередь, конечно же, разработчиков.

Добавление темизации в проект может быть крайне простой задачей, если эта задача ставится на этапах планирования проекта. Несмотря на то, что она стала популярна только в последние годы, сама эта технология совсем не нова. Этот процесс, как и многие другие отлаживался и активно развивался с каждым годом последние 5-10 лет. Сегодня даже страшно представить, как это делали первопроходцы. Нужно было поменять всем элементам классы, оптимизировать это через наследование цветов, обновлять почти весь ДОМ. А это все во временя такого монстра, как IE, снящегося в худших кошмарах бывалым разработчикам, и до появления ES6. Сейчас же, все эти проблемы уже далеки от разработчиков. Многие невероятно трудные процессы под влиянием времени постепенно уходят в былое, оставляя будущим поколениям разработчиков память о тех ужасных временах и прекрасные решения, доведенные во многом до идеала.

JS один из самых динамично развивающихся языков программирования, но в вебе развивается далеко не только он. Добавляются новые возможности и устраняются старые проблемы в таких технологиях, как HTML и CSS. Это, конечно же, невозможно без обновления и самих браузеров. Развитие и популяризация современных браузеров скидывают большой груз с плеч программистов. На этом все эти технологии не останавливаются и уверен, что через годы, о них будут отзываться также, как программисты сейчас отзываются об IE. Все эти обновления дают нам не только упрощение разработки и повышение ее удобства, но и добавляет ряд новых возможностей. Одной из таких возможностей стали переменные в css, впервые появившиеся в браузерах в 2015 году. 2015 год во многом получился знаменательным для веба это исторически важное обновления JS, утверждения стандарта HTTP/2, появление WebAssembly, популяризация минимализма в дизайне и появление ReactJS. Эти и многие другие нововведения нацелены на ускорение сайта, упрощение разработки и повышение удобства взаимодействия с интерфейсом.

Немного из истории css-переменных:

Первое упоминание переменных, которое мне удалось откопать, числится за 2012 годом. В апреле сего года в документации появилось описание новой концепции для css переменные.

Был описан весьма интересный способ создания и использования переменных:

:root {  var-header-color: #06c;}h1 { background-color: var(header-color); }

Однако, до появления этой функциональности в браузерах, должно было пройти значительное время на продумывание и отладку. Так, впервые поддержка css-переменных была добавлена в firefox лишь в 2015 году. Затем, в 2016, к нему присоединились google и safari.

Итоговая реализация отличалась от первоначальной идеи и выглядела следующим, уже привычным нам, образом:

:root {  --header-color: #06c;}h1 { background-color: var(--header-color); }

Впервые, такой способ описания переменных, был описан в документации в 2014 году. В том же году появилось описание значения по умолчанию второго аргумента данной функции.

Также, интересно проследить цели добавления переменных. Судя по первым версиям спецификации таковыми были возможность избавиться от дублирования констант и улучшение возможностей для разработки адаптивности. В 2015 году появился пример с использованием для интернационализации. О темизации в том далеком и важном для фронтенда году, речи практически не шло тренд на нее появился лишь в последние несколько лет.

Переменные открыли большой потенциал не только в темизации, но и гибкости дизайна в целом. Раньше для обновления цвета, например кнопки отмены нужно было пройти по всем файлам, найти все классы, которые означают отмену и обновить их цвета. Теперь же, стандартом является создание переменной, а всем элементам, подразумевающим действие отмены, в качества цвета используется непосредственно она. Если однажды, дизайнер решит, что эта кнопка должна быть теперь не красная, а алая он может смело это предложить, не боясь быть закиданным камнями за минорное обновление при всей его сложности.

В параллель спецификации Css развиваются также его пре и постпроцессоры. Их развитие было значительно быстрее, так как им не нужно было описывать спецификацию и продвигать ее во все браузеры. Одним из первых препроцессоров был stylus, созданный в далеком 2011, позднее были созданы sass и less. Они дают ряд преимуществ и возможностей, за счет того, что все сложные функции и модификации во время сборки конвертируются в css. Одной из таких возможностей являются переменные. Но это уже совершенно иные переменные, больше похожие на js, нежели css. В сочетании с миксинами и js можно было настроить темизацию.

Прошло уже 10 лет с появления препроцессора, гигантский отрезок по меркам веба. Произошло множество изменений и дополнений. HTML5, ES6,7,8,9,10. JS обзавелся целым рядом библиотек, отстроив вокруг себя невообразимый по масштабам зверинец. Некоторые из этих библиотек стали стандартом современного веба react, vue и angular, заменив привычный разработчикам HTML на свои альтернативы, основанные на js. JS заменяет и css, сделав такую замечательную технологию, как css in js, дающую те же возможности, но только динамичнее и в привычном формате (порою большой ценой, но это уже совсем другая история). JS захватил веб, а затем перешел на захват всего мира.

Темы нужны современному миру и раз уж это так, значит дизайнером нужно знать, как их спроектировать, а разработчикам как это реализовать. Самих способов реализации, как уже было описано немало. Не меньше тонкостей и потенциальных проблем, которые могут появляться в ходе развития этой возможности.

Проектирование дизайна

Как уже говорилось, гораздо лучше, если идея добавления тем появилась на зарождении проекта. Можно сразу заложить фундамент и продолжать с его учетом. Ведь это явно проще, чем закладывать фундамент после постройки дома. Хотя, справедливости ради, стоит отметить, что если дома проектировались как модульные, с учетом расширения и передвижений то это будет возможно и без дополнительных усилий.

Так как тема это элемент интерфейса часть работ по планированию возьмут на себя дизайнеры. Подходы к разработке дизайн-систем не стоят на месте. Если раньше дизайн сайта разрабатывали в программах, подобных фотошопу (хотя есть отдельные личности, которые занимаются подобным и сейчас, доводя разработчиков до состояния истинного ужаса). У них была масса минусов, особенно во времена медленных компьютеров и больших идей клиентов. Конечно же, эти программы не канут в лету, они будут использоваться по их основному назначению обработка фотографий, рисование иллюстраций. Их роль получают современные альтернативы, предназначенные в первую очередь для веба Avocode, Zeplin, Figma, Sketch. Удобно, когда основные инструменты, используемые программистом предназначены именно для целей разработки. В таких случаях, развитие инструментов идет в ногу с развитием сфер, для которых они предназначены. Эти инструменты являются отличным тому подтверждением. Когда они появились в них можно было копировать css стили, делать сетки, проверять margin-ы и padding-и. Не прямоугольниками и даже не линейкой, а просто движением мыши. Затем появились переменные, после в мир веба пришел компонентный подход и этот подход появился в данных инструментах. Они следят за тенденциями, делая те или иные утилиты, добавляют наборы инструментов и не останавливаются на всем этом, чудесным образом поспевая за этой, разогнавшейся до невероятных скоростей, машиной.

Одно из основных преимуществ компонентного подхода переиспользуемость. Один и тот же элемент можно вставить в любое место и затем менять их все сразу, легким движением руки. Но это примечательно не только копированием в оригинальном виде, но и с небольшими изменениями. Одним из таких изменений может быть цвет.

Темизация может выходить и за рамки страницы сайта. Одной из таких возможностей является цвет строки состояния и вкладки в некоторых мобильных браузерах. Для этих элементов также стоит продумать оттенки.

Цветовая гамма

Просматривая дизайн нового проекта, часто можно заметить странный, но весьма популярный способ именования цветов blue200. Конечно же, за подобное можно сказать спасибо дизайнеру, ведь это тоже верный подход, однако для иных целей. Такой способ хорошо подходит, если разработчики будут использовать атомарный css, ставшим в последние годы самым интересным и приятным для разработчиков, но все еще значительно отстающим по использованию от БЭМ-а [ист.]. Однако, ни такой способ именования переменных, ни атомарный css не годятся для сайтов, которые проектируются с учетом темизации. Причин тому много, одна из них заключается в том, что blue200 это всегда светло-синий цвет и для того, чтобы цвет у всех светло-синих кнопок стал темно-синим нужно у всех кнопок поменять его на blue800. Значительно более верным вариантом будет назвать цвет primary-color, потому что такое имя может быть как blue200, так и blue800, но всем участникам разработки будет понятно, что эта переменная означает основной цвет сайта.

colors: {  body: '#ECEFF1',  antiBody: '#263238',  shared: {    primary: '#1565C0',    secondary: '#EF6C00',    error: '#C62828',    default: '#9E9E9E',    disabled: '#E0E0E0',  },},

Для текста можно использовать схему подобную кнопкам (основной, второстепенный, по умолчанию, для отключенных элементов), а можно использовать уровни цвета:

colors: {  ...  text: {    lvl1: '#263238',    lvl3: '#546E7A',    lvl5: '#78909C',    lvl7: '#B0BEC5',    lvl9: '#ECEFF1',  },},

То есть основной цвет, цвет для текста 2-го уровня и т.д. При переключении на темную тему эти уровни инвертируются и интерфейс будет также хорошо выглядеть.

Примеры названия переменных:

shared-primary-color,

text-lvl1-color.

Конечно же, подобный способ именования переменных не может быть абсолютно универсальным, однако он (при незначительных изменениях) подойдет для большинства случаев.

Теперь, разобравшись с проектированием дизайна в контексте разработки, можно переходить на следующий этап.

Проектирование кода.

Как уже говорилось, на уровне кода есть 3 основных пути проектирования темизации через нативные переменные (с препроцессорами или без), через css in js, через замену файлов стилей. Каждое решение может так или иначе свестись к нативным переменным, но беда заключается в том, что в IE нет их поддержки. Дальше будет описано 2 варианта проектирования темизации с помощью переменных на нативном css и с помощью css in js.

Основные шаги при темизации сайта:

  1. Создание стилей каждой темы (цвета, тени, рамки);

  2. Настройка темы по умолчанию, в зависимости от темы устройства пользователя (в случае с темной и светлой темой);

  3. Настройка манифеста и мета тегов;

  4. Создание стилизованных компонентов;

  5. Настройка смены темы при нажатии на кнопку;

  6. Сохранение выбранной темы на устройстве пользователя.

Третий шаг универсален для любого варианта темизации. Поэтому, сперва кратко о нем.

Манифест это файл, используемый, в первую очередь, для PWA. Однако, его содержимое является альтернативой метатегам и загружается быстрее них. В случае темизации нас интересуют такие ключи, как theme_color и background_color. Мети-теги с этими параметрами также можно добавить в head страницы.

Theme_color цвет темы сайта. Указанный цвет будет использоваться в качестве цвета вкладки и строки состояния на мобильных устройствах на системе Android. У данного функционала крайне скудная поддержка браузеров, однако доля этих браузеров составляет 67%.

caniuse.comcaniuse.com

Background_color цвет, который будет загружаться до загрузки стилей. Поддержка данного атрибута еще более скудная, чем у цвета темы:

caniuse.comcaniuse.com

Переменные

Начать описание этого варианта стоит с поддержки, так как это, пожалуй, его единственный минус.

caniuse.comcaniuse.com

Полное отсутствие поддержки в IE, долгое ее отсутствие в популярных браузерах и в Safari являются не критическими проблемами, но ощутимыми, хоть и соотносятся с фриками, не готовыми обновлять свои браузеры и устройства. Однако, IE все еще используется и даже популярнее Safari (5,87% против 3,62% по данным на 2020г).

Теперь о реализации данного способа.

1. Создание классов dark и light, содержащих переменные темы.

Способ именования переменных описан в разделе Проектирование дизайна.

В классах темы должны храниться все переменные, используемые для темизации.

.theme-light {  --body-color: #ECEFF1;  --antiBody-color: #263238;  --shared-primary-color: #1565C0;  --shared-secondary-color: #EF6C00;  --shared-error-color: #C62828;  --shared-default-color: #9E9E9E;  --shared-disabled-color: #E0E0E0;  --text-lvl1-color: #263238;  --text-lvl3-color: #546E7A;  --text-lvl5-color: #78909C;  --text-lvl7-color: #B0BEC5;  --text-lvl9-color: #ECEFF1;}.theme-dark {--body-color: #263238;  --antiBody-color: #ECEFF1;  --shared-primary-color: #90CAF9;  --shared-secondary-color: #FFE0B2;  --shared-error-color: #FFCDD2;  --shared-default-color: #BDBDBD;  --shared-disabled-color: #616161;  --text-lvl1-color: #ECEFF1;  --text-lvl3-color: #B0BEC5;  --text-lvl5-color: #78909C;  --text-lvl7-color: #546E7A;  --text-lvl9-color: #263238;}

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

2. Настройка класса по умолчанию, в зависимости от темы устройства пользователя.

Если основная цель темизации сайта добавление темной темы, то вам стоит озаботиться этим пунктом. Верная настройка даст пользователям крайне приятный опыт и не ослепит их, если они придут на ваш сайт в поздние часы, в поисках ценного контента.

Для решения этой задачи есть как минимум 2 корректных подхода

2.1) Настройка темы по умолчанию внутри css

Добавляется новый класс, который устанавливается по умолчанию - .theme-auto

Для этого класса добавляются переменные в зависимости от темы устройства посредством media запросов:

@media (prefers-color-scheme: dark) {body.theme-auto {--background-color: #111;--text-color: #f3f3f3;}}@media (prefers-color-scheme: light) {body.theme-auto {--background-color: #f3f3f3;    --text-color: #111;}}

Плюсы данного способа:

  • отсутствие скриптов

  • быстрое выполнение

Минусы:

  • дублирование кода (переменные повторяются с .theme-dark и .theme-light)

  • для определения темы, выбранной при последнем посещении все-равно потребуется скрипт

2.2) Установка класса по умолчанию с помощью js

У js есть полезная функция отслеживание и проверка правил css. Одним из таких правил, как уже было описано выше, является тема устройства пользователя.

Для проверки темы и добавления класса нужной темы нужно добавить следующий код:

if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {body.classlist.add('theme-dark')} else {body.classlist.add('theme-light')}

Дополнительно вы можете подписаться на изменение темы устройства:

window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => {    if (e.matches) {        body.classlist.remove('theme-light')        body.classlist.add('theme-dark')    } else {        body.classlist.remove('theme-dark')        body.classlist.add('theme-light')    }});

Плюсы:

  • отсутствие дублирования переменных

Минусы:

  • Чтобы не было прыжков темы данный код должен выполняться на верхнем уровне (head или начало body). То есть он должен выполняться отдельно от основного бандла.

3. Создание стилизованных классов для элементов

./button.css

.button {  color: var(--text-lvl1-color);  background: var(--shared-default-color);  ...  &:disabled {    background: var(--shared-disabled-color);  }}.button-primary {background: var(--shared-primary-color);}.button-secondary {background: var(--shared-secondary-color)}

./appbar.css

.appbar {display: flex;  align-items: center;  padding: 8px 0;  color: var(--text-lvl9-color);  background-color: var(--shared-primary-color);}

4. Настройка смены класса при нажатии на кнопку смены темы

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

  • удалять прошлые классы, связанные с темой:

body.classlist.remove('theme-light', 'theme-high')
  • добавлять класс выбранной темы:

body.classlist.add('theme-dark')

5. Сохранение выбранной темы на устройстве пользователя.

Тему можно сохранять как в куки, так и в локальном хранилище. Структура и в первом, и во втором случае будет одинаковая: theme: 'light' | 'dark' | 'rose'

На верхнем уровне сайта нужно добавить получение сохраненной темы и добавление нужного класса тегу body. Например, в случае с локальным хранилищем:

const savedTheme = localStorage.getItem('theme')if (['light', 'dark', 'rose'].includes(savedTheme)) {body.classlist.remove('theme-light', 'theme-dark', 'theme-rose')body.classList.add(`theme-${savedTheme}`)}

То есть, если сохраненная тема одна из настроенных тем, то мы удаляем классы, добавленные по умолчанию, и добавляем класс с сохраненной темой.

Css-in-js

Данный вариант больше всего подходит для приложения, выполняемых на стороне клиента.

В качестве примера будет показана связка React + styled-components + typescript.

1. Создание объектов dark и light, содержащих переменные темы.

Способ именования переменных описан в разделе Проектирование дизайна.

В объектах темы должны храниться все переменные, используемые для темизации.

Вы должны решить, какая тема будет использоваться по умолчанию и передать нужный объект Provider-у.

./App.tsx

import { useState } from 'react'import { ThemeProvider } from 'styled-components'import themes from './theme'const App = () => {const [theme, setTheme] = useState<'light' | 'dark'>('light')const onChangeTheme = (newTheme: 'light' | 'dark') => {setTheme(newTheme)}return (<ThemeProvider theme={themes[theme]}>// ...</ThemeProvide>)}

2. Настройка класса по умолчанию, в зависимости от темы устройства пользователя.

Если основная цель темизации сайта добавление темной темы, то вам стоит озаботиться этим пунктом. Верная настройка даст пользователям крайне приятный опыт и не ослепит их, если они придут на ваш сайт в поздние часы, в поисках ценного контента.

Для этого можно настроить тему по умолчанию на верхнем уровне приложения:

useEffect(() => {  if (window.matchMedia?.('(prefers-color-scheme: dark)').matches) {    onChangeTheme('dark')  }}, [])

Дополнительно вы можете подписаться на изменение темы устройства:

useEffect(() => {  window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {    if (e.matches) {      onChangeTheme('dark')    } else {      onChangeTheme('light')    }  })}, [])

3. Создание стилизованных компонентов

./src/components/atoms/Button/index.tsx - git

import type { ButtonHTMLAttributes } from 'react'import styled from 'styled-components'interface StyledProps extends ButtonHTMLAttributes<HTMLButtonElement> {  fullWidth?: boolean;  color?: 'primary' | 'secondary' | 'default'}const Button = styled.button<StyledProps>(({ fullWidth, color = 'default', theme }) => `  color: ${theme.colors.text.lvl9};  width: ${fullWidth ? '100%' : 'fit-content'};  ...  &:not(:disabled) {    background: ${theme.colors.shared[color]};    cursor: pointer;    &:hover {      opacity: 0.8;    }  }  &:disabled {    background: ${theme.colors.shared.disabled};  }`)export interface Props extends StyledProps {  loading?: boolean;}export default Button

./src/components/atoms/AppBar/index.tsx - git

import styled from 'styled-components'const AppBar = styled.header(({ theme }) => `  display: flex;  align-items: center;  padding: 8px 0;  color: ${theme.colors.text.lvl9};  background-color: ${theme.colors.shared.primary};`)export default AppBar

4. Настройка смены класса при нажатии на кнопку смены темы

Через context api или redux/mobx изменяется имя текущей темы

./App.tsx - git

import { useState } from 'react'import { ThemeProvider } from 'styled-components'import themes from './theme'const App = () => {  const [theme, setTheme] = useState<'light' | 'dark'>('light')  const onChangeTheme = (newTheme: 'light' | 'dark') => {    setTheme(newTheme)  }  return (    <ThemeProvider theme={themes[theme]}>    <ThemeContext.Provider value={{ theme, onChangeTheme }}>    ...</ThemeContext.Provider>    </ThemeProvide>)}

.src/components/molecules/Header/index.tsx - git

import { useContext } from 'react'import Grid from '../../atoms/Grid'import Container from '../../atoms/Conrainer'import Button from '../../atoms/Button'import AppBar from '../../atoms/AppBar'import ThemeContext from '../../../contexts/ThemeContext'const Header: React.FC = () => {  const { theme, onChangeTheme } = useContext(ThemeContext)  return (    <AppBar>      <Container>        <Grid container alignItems="center" justify="space-between" gap={1}>          <h1>            Themization          </h1>          <Button color="secondary" onClick={() => onChangeTheme(theme === 'light' ? 'dark' : 'light')}>            set theme          </Button>        </Grid>      </Container>    </AppBar>  )}export default Header

5. Сохранение выбранной темы на устройстве пользователя.

Тему можно сохранять как в куки, так и в локальном хранилище. Структура и в первом, и во втором случае будет одинаковая: theme: 'light' | 'dark' | 'rose'

На верхнем уровне сайта нужно добавить получение сохраненной темы и обновлять значение текущем темы. Например, в случае с локальным хранилищем:

./App.tsx - git

...function App() {  const [theme, setTheme] = useState<'light' | 'dark'>('light')  const onChangeTheme = (newTheme: 'light' | 'dark') => {    localStorage.setItem('theme', newTheme)    setTheme(newTheme)  }  useEffect(() => {    const savedTheme = localStorage?.getItem('theme') as 'light' | 'dark' | null    if (savedTheme && Object.keys(themes).includes(savedTheme)) setTheme(savedTheme)    else if (window.matchMedia?.('(prefers-color-scheme: dark)').matches) {      onChangeTheme('dark')    }  }, [])  useEffect(() => {    window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {      if (e.matches) {        onChangeTheme('dark')      } else {        onChangeTheme('light')      }    })  }, [])  return (  ...  )}

Финальный код

Демо

Итоги

Вариантов внедрения темизации много от создания файлов со всеми стилями для каждой темы и их смены при необходимости до css-in-js решений (с нативными css переменными или встроенными в библиотеки решениями). Браузерное api дает возможности для настройки сервиса под каждого конкретного пользователя, считывая и отслеживая тему его устройства.

Темизация набирает обороты, крупные компании одна за другой внедряют ее в свои сервисы. Правильная темная тема улучшает пользовательский опыт, уменьшает нагрузку на глаза, экономит заряд батареи, дает столь желаемую возможность кастомизации сервиса под себя. Много плюсов, при невысокой цене, особенно, если все планируется заранее.

Конечно же, темизация нужна не всем. В любом случае она связана с, пусть и небольшими, но все же усложнениями. Она нужна, например, для приложений и веб-сервисов.

Сервисы Google и apple, банки, соц. сети, редакторы, github и gitlab. Продолжать список можно бесконечно, несмотря на то, что это только начало развития технологии, а дальше больше, лучше и проще.

Подробнее..

Перевод - recovery mode Темный режим Hello darkness, my old friend

14.10.2020 20:13:37 | Автор: admin
Dark mode остается главной тенденцией в дизайне сайтов и приложений. Мы нашли классную статью на эту тему и решили поделиться переводом. Мнение пользователей, реализация и поддержка dark mode, рекомендации для разработчиков далее в статье. А на какой стороне вы?

Просто хайп или необходимость? Узнайте больше о темном режиме. Я расскажу, как добавить поддержку dark mode на благо ваших пользователей!

Введение


По данной теме я провел объемное исследование, изучил историю вопроса. Если вас интересует только работа с темным режимом, смело пропускайте первый раздел.

Темный режим до того, как это стало мейнстримом


Зеленый экран (источник)

Говорят, история циклична. В ситуации с темным режимом мы вернулись к тому, с чего всё и начиналось. На заре эры персональных компьютеров использование темного режима было единственно возможным вариантом: монохромные ЭЛТ-мониторы работали, облучая пучками электронов фосфоресцирующий экран, а люминофор, использовавшийся в ранних ЭЛТ, был зеленым. Поскольку текст отображался зеленым цветом, а остальная часть экрана была черной, такие модели часто назывались зелеными экранами.

Темное на белом (источник)

Впоследствии цветные ЭЛТ-дисплеи стали отображать несколько цветов за счет использования красного, зеленого и синего люминофоров. Они создавали белый цвет, активируя все три люминофора одновременно. С появлением более современных настольных издательских систем и технологии WYSIWYG стала популярной идея сделать виртуальный документ похожим на реальный лист бумаги.

Браузер WorldWideWeb (источник)

В этот момент в дизайне и зародился тренд темное на белом, его реализовали в самых первых веб-сайтах сети они больше походили на текстовые документы.

Первый в мире браузер WorldWideWeb (представьте, CSS еще не был изобретен) отображал веб-страницы именно так. Забавный факт: второй в истории браузер Line Mode Browser (браузер на основе терминала) был зеленым на темном. Сейчас веб-страницы и приложения обычно создаются с темным текстом на светлом фоне, что является общепринятой нормой. Такая цветовая схема встроена в таблицы стилей современных пользовательских агентов, включая, например, Chrome.


Использование смартфонов (источник)

Дни ЭЛТ-мониторов давно прошли. Огромную часть контента теперь мы потребляем и создаем на мобильных устройствах, которые используют ЖК-дисплеи с подсветкой или энергосберегающие AMOLED-дисплеи. Меньшие по размеру и более практичные в использовании компьютеры, планшеты и смартфоны привели к новым моделям поведения пользователей. В свободное время мы пропадаем в социальных сетях, программируем ради развлечения или играем в компьютерные игры. Обычно это происходит после работы вечером при тусклом освещении или даже ночью в кровати перед сном. Чем больше людей пользуются девайсами в темноте, тем более популярным становится использование темного режима.

Почему мы выбираем темный режим?


По эстетическим соображениям
Когда людей спрашивают, почему им нравится темный режим, самые популярные ответы: Он приятнее для глаз или Темный режим красивый. Компания Apple в документации для разработчиков темного режима открыто говорит: Выбор темного или светлого интерфейса для большинства пользователей происходит на основе эстетических предпочтений и может не иметь отношения к условиям освещения.

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


System 7 CloseView (источник)

Темный режим как инструмент доступности для людей с ограниченными возможностями здоровья
Некоторым людям использование темного режима просто необходимо: например, пользователи с ослабленным зрением используют такой режим как инструмент доступности. Самый ранний случай применения темного режима в качестве инструмента доступности, который я смог найти, это функция CloseView в ОС System 7 с возможностью менять цветовую схему: черное на белом и белое на черном. Хотя System 7 поддерживала цветной интерфейс, пользовательский интерфейс по умолчанию оставался черно-белым.

Этот метод на основе инверсии, продемонстрировал свои слабые стороны после увеличения количества цветов в интерфейсе. Сарит Сзпиро (Sarit Szpiro) с командой исследователей провели опрос пользователей о том, как люди с ограниченным зрением обращаются с компьютерными устройствами. В результате оказалось, что все опрошенные не любили инвертированные цвета, но многие предпочитали светлый текст на темном фоне. Компания Apple учитывает данное предпочтение пользователей с помощью функции Smart Invert, которая меняет цвета на дисплее, за исключением изображений, мультимедиа и некоторых приложений, использующих стили темного цвета.

Особой формой слабовидения является синдром компьютерного зрения, также известный как цифровое напряжение зрения. Этими терминами обозначают различные проблемы со зрением, которые связаны с частым использованием компьютеров (настольные компьютеры, ноутбуки и планшеты) и других электронных устройств (смартфоны и электронные книги). Ученые предполагают, что использование подростками электронных устройств, особенно в ночное время, приводит к повышенному риску появления проблем со сном, бессонницы и синдрома недостаточности сна. Согласно другим исследованиям, воздействие синего света участвует в регуляции циркадного ритма и цикла сна, а нерегулярная световая среда может привести к депривации сна, что влияет на настроение человека и его эффективность при выполнении задач. Ограничить негативное влияние можно, уменьшив количество синего света с помощью регулировки цветовой температуры дисплея (такие функции, как iOS Night Shift или Android Night Light), а также предотвращая яркий или нерегулярный свет в целом благодаря темной теме или режиму.

Экономия энергии в темном режиме на AMOLED-дисплеях

Известно, что темный режим экономит много энергии на AMOLED-дисплеях. Исследования, посвященные популярным приложениям Google таким, как YouTube, доказали, что экономия энергии может достигать 60%. В видео ниже дана более подробная информация об этих исследованиях и экономии энергии для каждого приложения.



Как активировать темный режим в операционной системе


Теперь, когда я рассказал, почему темный режим так важен для многих пользователей, давайте рассмотрим, как вы можете его настроить.


Настройки темной темы на Android Q

Операционные системы, поддерживающие темный режим или темную тему, обычно имеют возможность активировать их в настройках. В macOS X это находится в разделе Общие системных настроек и называется Appearance (снимок экрана), а в Windows 10 в разделе Colors под названием Choose your color (снимок экрана). Для Android Q вы можете переключить режим в Display as a Dark Theme (снимок экрана), а в iOS 13 изменить цвет интерфейса можно в разделе Display & Brightness (снимок экрана).

Медиа-запрос prefers-color-scheme


Еще немного теории, прежде чем я продолжу. Медиа-запросы позволяют авторам тестировать и запрашивать значения и свойства пользовательского агента или устройства независимо от отрисовки документа. Они используются в CSS медиа-правиле для условного применения стилей к документу и в некоторых других контекстах и языках таких, как HTML и JavaScript. Медиа-запросы уровня 5 вводят так называемые предпочтительные для пользователя медиа-свойства, что является сигналом для сайтов обнаружить предпочтительный для юзера способ отображения контента.

Установленное CSS медиа-свойство prefers-reduced-motion может использоваться для определения того, запрашивает ли пользователь, чтобы ОС минимизировала количество анимации, которое она использует. Я уже писал о prefers-reduced-motion ранее.

CSS медиа-свойство prefers-color-scheme используется для определения, какая тема, светлая или тёмная, используется человеком в операционной системе. Оно работает со следующими значениями:
  • no-preference: Указывает, что пользователь не сделал никаких предпочтений, известных системе. Это ключевое слово оценивается как ложное в логическом контексте.
  • light: указывает, что пользователь уведомил систему, что он предпочитает страницу со светлой темой (темный текст на светлом фоне).
  • dark: указывает, что пользователь уведомил систему, что он предпочитает страницу с темной темой (светлый текст на темном фоне).

Поддержка темного режима


Выясним, поддерживается ли темный режим браузером


Поскольку темный режим сообщается через медиа-запрос, вы можете легко проверить, поддерживает ли текущий браузер темный режим, выяснив, подходит ли медиа-запрос prefers-color-scheme. Обратите внимание, что я не устанавливаю значение, а просто проверяю медиа-запрос на соответствие.

if (window.matchMedia('(prefers-color-scheme)').media !== 'not all') {  console.log(' Dark mode is supported');}

На момент написания статьи prefers-color-scheme поддерживается как на настольных компьютерах, так и на мобильных устройствах (где доступно) в Chrome и Edge с версии 76, Firefox с версии 67 и Safari с версии 12.1 в macOS и с версии 13 на iOS. Для всех других браузеров информацию вы можете найти в статье Can I use support tables.

Доступен настраиваемый элемент <dark-mode-toggle>, который добавляет поддержку темного режима в старые браузеры. Об этом я напишу далее.

Темный режим на практике


Давайте рассмотрим, как на практике выглядит поддержка темного режима. Так же, как в фильме Горец, в конце может остаться только один: темный или светлый! Почему я акцентирую на этом внимание? Потому что этот факт влияет на стратегию загрузки. Пожалуйста, не заставляйте пользователей скачивать CSS на критическом этапе рендеринга для режима, который сейчас не используется. Следовательно для оптимизации скорости загрузки я разделил мой CSS в примере на три части с целью отложить загрузку некритического CSS:

  • style.css содержит общие правила, которые используются на всем сайте
  • dark.css содержит правила, необходимые для темного режима
  • light.css содержит правила, необходимые только для светлого режима.

Стратегия загрузки


Два последних, light.css и dark.css, загружаются выборочно через запрос <link media>.

Изначально не все браузеры поддерживают CSS медиа-свойство prefers-color-scheme (обнаруживаемое с помощью примера выше), это решается выбором light.css по умолчанию через элемент в нашем встроенном скрипте (light это произвольный выбор, я также мог бы сделать dark по умолчанию). Чтобы избежать появления нестилизованного содержимого, я скрываю содержимое страницы до тех пор, пока не загрузится light.css.

<script>  // If `prefers-color-scheme` is not supported, fall back to light mode.  // In this case, light.css will be downloaded with `highest` priority.  if (window.matchMedia('(prefers-color-scheme)').media === 'not all') {    document.documentElement.style.display = 'none';    document.head.insertAdjacentHTML(        'beforeend',        '<link rel="stylesheet" href="http://personeltest.ru/aways/habr.com/light.css" onload="document.documentElement.style.display = ``">'    );  }</script><!--  Conditionally either load the light or the dark stylesheet. The matching file  will be downloaded with `highest`, the non-matching file with `lowest`  priority. If the browser doesn't support `prefers-color-scheme`, the media  query is unknown and the files are downloaded with `lowest` priority (but  above I already force `highest` priority for my default light experience).--><link rel="stylesheet" href="http://personeltest.ru/aways/habr.com/dark.css" media="(prefers-color-scheme: dark)"><link rel="stylesheet" href="http://personeltest.ru/aways/habr.com/light.css" media="(prefers-color-scheme: no-preference), (prefers-color-scheme: light)"><!-- The main stylesheet --><link rel="stylesheet" href="http://personeltest.ru/aways/habr.com/style.css">

Архитектура таблицы стилей


Я использую переменные CSS, что позволяет стилю style.css быть универсальным, вся настройка светлого или темного режима происходит в двух других файлах: dark.css и light.css. Ниже приведен пример, которого должно быть достаточно, чтобы объяснить общую идею. Я объявляю две переменные, --color и --background-color, которые создают основную тему темный на светлом и светлый на темном.

/* light.css:  dark-on-light */:root {  --color: rgb(5, 5, 5);  --background-color: rgb(250, 250, 250);}/* dark.css:  light-on-dark */:root {  --color: rgb(250, 250, 250);  --background-color: rgb(5, 5, 5);}

Затем в style.css я использую эти переменные в body {}. Поскольку они определены в CSS псевдо-классе :root селекторе, который в HTML представляет элемент <html> и идентичен селектору html, за исключением того, что его специфичность выше: переменные каскадно наследуются, таким образом позволяя определить глобальные CSS переменные.

/* style.css */:root {  color-scheme: light dark;}body {  color: var(--color);  background-color: var(--background-color);}

В приведенном выше примере вы, вероятно, заметили свойство color-scheme со значениями light dark, разделенными пробелом.

Свойство сообщает браузеру, какие цветовые темы поддерживает мое приложение, и позволяет ему активировать специальные варианты таблицы стилей пользовательского агента. Это полезно, например, для того, чтобы позволить браузеру отображать поля формы с темным фоном и светлым текстом, настраивать полосы прокрутки или чтобы включить цвет выделения с учетом темы. Детали свойства color-scheme указаны в CSS Color Adjustment Module Level 1.

Узнайте больше о color-scheme.

Все остальное это просто определение CSS стилей для остальной разметки, которая есть на моем сайте. Семантическая организация стилей очень помогает при работе с темным режимом. Например, вместо --highlight-yellow рассмотрите возможность названия переменной --accent-color, так как желтый на самом деле может не быть желтым в темном режиме или наоборот. Ниже приведен пример еще нескольких переменных, которые я использую.

/* dark.css */:root {  --color: rgb(250, 250, 250);  --background-color: rgb(5, 5, 5);  --link-color: rgb(0, 188, 212);  --main-headline-color: rgb(233, 30, 99);  --accent-background-color: rgb(0, 188, 212);  --accent-color: rgb(5, 5, 5);}/* light.css */:root {  --color: rgb(5, 5, 5);  --background-color: rgb(250, 250, 250);  --link-color: rgb(0, 0, 238);  --main-headline-color: rgb(0, 0, 192);  --accent-background-color: rgb(0, 0, 238);  --accent-color: rgb(250, 250, 250);}

Подробный разбор


В следующей вставке Glitch вы можете увидеть пример, в котором используется все, что описано выше, на практике. Попробуйте переключить темный режим в настройках вашей операционной системы и посмотрите, как отреагирует страница.

Влияние на скорость загрузки


Когда вы наиграетесь с этим примером, вы поймете, почему я загружаю свои dark.css и light.css через медиа-запросы. Попробуйте переключить темный режим и перезагрузить страницу: определенные, в настоящее время несовпадающие таблицы стилей все еще загружаются, но с самым низким приоритетом, чтобы они не конкурировали с ресурсами, которые необходимы сайту прямо сейчас.

Узнайте, почему браузеры загружают таблицы стилей с несовпадающими медиа-запросами.

Сайт в светлом оформлении загружает стили для темного оформления с самым низким приоритетом:


Сайт в темном оформлении загружает стили для светлого оформления с самым низким приоритетом:


Сайт по умолчанию в светлом оформлении в браузере, который не поддерживает prefers-color-scheme, загружает стили для темного оформления с самым низким приоритетом:


Как реагировать на изменения темного режима


Как и на любое другое изменение медиа-запроса, на изменение темного режима можно подписаться через JavaScript. Вы можете использовать это, например, для динамического изменения значка страницы или изменения <meta name = "theme-color">, которое определяет цвет строки URL-адреса в Chrome. Пример выше показывает описанное в действии. Чтобы увидеть изменения цвета темы и значка, откройте демонстрацию в отдельной вкладке.

const darkModeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)');  darkModeMediaQuery.addListener((e) => {    const darkModeOn = e.matches;    console.log(`Dark mode is ${darkModeOn ? ' on' : ' off'}.`);  });

Лучшие практики темного режима


Избегайте абсолютно белого

Вы могли заметить маленькую деталь: я не использую чисто белый цвет. Вместо этого, чтобы предотвратить свечение на фоне окружающего темного содержимого, я выбрал немного более темный белый цвет, что-то вроде rgb (250, 250, 250).

Изменение цвета и затемнение фотоизображений

Если вы сравните два скриншота ниже, вы заметите, что не только основная тема изменилась с темного на светлом на светлый на темном, но и изображение выглядит немного иначе. Мой опрос показал, что большинство пользователей предпочитают чуть менее яркие и насыщенные изображения, когда активен темный режим. Я называю это перекрашиванием (re-colorization).

Цвета картинки становятся более тусклыми в темном режиме

Цвета картинки в светлом режиме

Перекрасить изображения можно с помощью фильтра CSS. Я использую селектор CSS, который подходит всем изображениям, не имеющим .svg в их URL-адресах. Идея заключается в том, что я могу дать векторной графике (иконкам) другую обработку, подробнее об этом в следующем разделе. Обратите внимание, как я снова использую переменную CSS, чтобы позже можно было быстро изменить свой фильтр.

Узнайте больше о предпочтениях пользователей из исследования.

Поскольку перекрашивание требуется только в темном режиме, то есть, когда dark.css активен, в light.css нет соответствующих правил.

/* dark.css */--image-filter: grayscale(50%);img:not([src*=".svg"]) {  filter: var(--image-filter);}

Настройка интенсивности перекрашивания темного режима с помощью JavaScript

Мы разные, и у каждого человека будут свои представления, как именно должен выглядеть темный режим. Придерживаясь метода перекрашивания, описанного выше, я легко могу сделать интенсивность оттенков серого предпочтением пользователя, которое изменяется с помощью JavaScript, а установив значение 0%, я могу полностью отключить перекрашивание. Обратите внимание, что document.documentElement предоставляет ссылку на корневой элемент документа, то есть на тот же элемент, на который я могу ссылаться с помощью CSS псевдо-класса:root.

const filter = 'grayscale(70%)';document.documentElement.style.setProperty('--image-filter', value);

Инвертировать векторную графику и иконки


Для векторной графики (в моем случае используется как иконки, на которые я ссылаюсь через элементы <img>) я использую другой метод перекрашивания. Хотя исследования показали, что людям не нравится инверсия фотографий, она очень хорошо работает для большинства иконок. Я снова использую переменные CSS для определения степени инверсии в обычном состоянии и в состоянии :hover.

Иконка инвертируется в темном режиме:



Иконка в светлом режиме:



Обратите внимание, как снова я инвертирую иконки только в dark.css, но не в light.css, и как :hover получает различную интенсивность инверсии в двух случаях, чтобы иконка выглядела немного темнее или немного ярче, в зависимости от режима, выбранного пользователем.

/* dark.css */--icon-filter: invert(100%);--icon-filter_hover: invert(40%);img[src*=".svg"] {  filter: var(--icon-filter);}/* light.css */--icon-filter_hover: invert(60%);/* style.css */img[src*=".svg"]:hover {  filter: var(--icon-filter_hover);}

Используйте currentColor для inline SVG


Вместо использования инверсии фильтров для inline SVG изображений, вы можете добавить ключевое слово currentColor, которое представляет собой значение цвета элемента.

Это позволяет вам устанавливать значение цвета для свойств, которые не получают его по умолчанию. На самом деле, если currentColor используется как значение для атрибутов fill или stroke SVG, то он берет свое значение из унаследованного свойства цвета. Это также работает для <svg> <use href = ""> </svg>, поэтому у вас могут быть отдельные ресурсы, а currentColor по-прежнему будет применяться в контексте. Обратите внимание, что это работает только для inline или <use href = ""> SVG, но не для SVG, которые упоминаются как src изображения или через CSS. Подробнее здесь.

<!-- Some inline SVG --><svg xmlns="http://personeltest.ru/away/www.w3.org/2000/svg"    stroke="currentColor">  []</svg>

Плавные переходы между режимами


Переключение из темного режима в светлый или наоборот может быть сглажено благодаря тому факту, что цвет, и бэкграунд являются анимируемыми свойствами CSS. Создать анимацию так же просто, как объявить два перехода для двух свойств. Пример ниже иллюстрирует общую идею.

body {  --duration: 0.5s;   --timing: ease;  color: var(--color);  background-color: var(--background-color);  transition:    color var(--duration) var(--timing),    background-color var(--duration) var(--timing);}

Художественное оформление с темным режимом


Хотя из соображений производительности загрузки в целом я рекомендую работать исключительно с prefers-color-scheme в атрибуте media элементов (а не встроенным в таблицы стилей), есть ситуации, когда вы действительно можете захотеть работать с prefers-color- scheme встроенным в ваш HTML-код. Художественное оформление это как раз такая ситуация. Художественное оформление общее визуальное оформление страницы: как сайт воздействует на пользователя, какие чувства вызывает.

В темном режиме дизайнер должен решить, какое изображение выбрать и будет ли перекрашивание изображений подходящим. При использовании элемента <picture> <source> отображаемого изображения можно сделать зависимым от атрибута media. В приведенном ниже примере я показываю западное полушарие для темного режима и восточное полушарие для светлого режима или, когда настройки не заданы, по умолчанию как для восточного полушария в любом случае. Изображения, конечно, просто иллюстрируют мой пример. Включите темный режим на своем устройстве, чтобы увидеть разницу.

<picture>  <source srcset="western.webp" media="(prefers-color-scheme: dark)">  <source srcset="eastern.webp" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)">  <img src="eastern.webp"></picture>

Темный режим с возможностью отключения


Как упоминалось выше, большинство пользователей выбирают Dark Mode на основе своих вкусов и эстетических предпочтений. Некоторым пользователям нравится видеть UI своей ОС темным, а веб-страницы так, как они привыкли. План действий: сначала дождаться сигнала, который браузер отправляет через prefers-color-scheme, а затем позволить пользователям, если они хотят, переопределить настройки на уровне системы.

Кастомный элемент <dark-mode-toggle>


Вы, конечно, можете создать такой код самостоятельно, но можно просто использовать готовый элемент (веб-компонент), который я создал специально для этой цели. Он называется <dark-mode-toggle> и добавляет на вашу страницу переключатель (темный режим: вкл / выкл) или переключатель тем (тема: светлый / темный), который вы можете полностью настроить. Демо ниже показывает элемент в действии (о, и я незаметно использовал его во всех других примерах выше).

<dark-mode-toggle    legend="Theme Switcher"    appearance="switch"    dark="Dark"    light="Light"    remember="Remember this"></dark-mode-toggle>

<dark-mode-toggle> в светлом режиме:



<dark-mode-toggle> в темном режиме:



Попробуйте щелкнуть или коснуться элементов управления темным режимом в верхнем правом углу в демонстрации ниже. Если вы установите флажки в третьем и четвертом элементах управления, посмотрите, как ваш выбор режима запоминается даже при перезагрузке страницы. Это позволяет вашим посетителям поддерживать свою операционную систему в темном режиме, но наслаждаться вашим сайтом в светлом режиме или наоборот.

Заключение


Работа с темным режимом и его поддержка это весело! Открываются новые возможности для дизайна. Возможность выбора темного режима может сделать вашего пользователя более счастливым. Да, встречаются подводные камни, требуется тщательное тестирование, но темный режим отличная возможность, чтобы показать заботу о пользователях. Лучшие практики, упомянутые в статье, и такой лайфхак, как настраиваемый элемент <dark-mode-toggle>, должны помочь вам в создании потрясающего темного режима.

Полезные ссылки


Медиа-запрос prefers-color-scheme:


Мета-тег color-scheme:


Ссылки о dark mode:


Исследования:

Подробнее..

Nuxt.js app от UI-кита до деплоя. Часть 2 Темная тема

08.03.2021 02:20:33 | Автор: admin
Привет, Хабр!

Публикуем вторую часть цикла статей о создании современного блога на Nuxt.js. Сегодня реализуем тёмную тему в приложении, которое мы написали вместе с вами в первой части.

Обратите внимание, что код каждой части можно найти в собственной ветке на Github, а в master доступна версия приложения из последней опубликованной статьи.

Что такое темная тема?


Темная тема это цветовая схема любого интерфейса, которая отображает светлый текст и элементы интерфейса на темном фоне, что упрощает просмотр экрана на мобильных телефонах, планшетах и компьютерах при плохой освещенности. Темная тема уменьшает свет, излучаемый экраном, при сохранении минимального соотношения цветового контраста, необходимого для удобочитаемости.

Темная тема улучшает визуальную эргономику, снижая нагрузку на глаза, настраивая экран в соответствии с текущими условиями освещения и обеспечивая простоту использования в ночное время или в темноте.

Также нельзя забывать о том, что использование темной темы в веб- и мобильных приложениях может продлить срок службы батареи устройства. Компания Google подтвердила, что темная тема на OLED экранах очень помогает продлить срок службы батареи.

@nuxtjs/color-mode


Для реализации темной темы мы будем использовать модуль @nuxtjs/color-mode, который предоставляет следующие возможности:

  • добавляет класс .${color}-mode к тегу <html> для упрощения управлением темами 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 со следующим содержимым:

<template lang="pug">section.section  .content    .app-options      switcher-color-mode</template><script lang="ts">import Vue from 'vue'export default Vue.extend({  name: 'AppOptions',})</script><style lang="scss" scoped>.app-options {  display: flex;  margin-top: 24px;}</style>

Компонент на Github.

Как мы видим, в этом компоненте нет никакой логики, он просто устанавливает внешние отступы для вложенных компонентов. Сейчас у нас только один вложенный компонент switcher-color-mode, реализуем его.

Взглянем на секцию script этого компонента:

<script lang="ts">import Vue from 'vue'export default Vue.extend({  name: 'SwitcherColorMode',  computed: {    icon() {      return (this as any).$colorMode.value === 'light'        ? 'assets/icons/sun.svg'        : 'assets/icons/moon.svg'    },  },  methods: {    changeColorMode() {      ;(this as any).$colorMode.preference =        (this as any).$colorMode.value === 'light' ? 'dark' : 'light'    },  },})</script>

Здесь мы реализуем метод changeColorMode, который меняет тему в объекте, предоставляемом модулем @nuxtjs/color-mode.

При изменении значения $colorMode.preference также будет установлен соответствующий класс у тега html: class="light-mode" или class="dark-mode".

Кроме того, здесь есть вычисляемое свойство icon, которое возвращает нужную нам иконку в зависимости от выбранной темы. Обратите внимание, что для корректной работы нужно добавить иконки sun.svg и moon.svg в директорию assets/icons.

Шаблон компонента будет выглядеть следующим образом:

<template lang="pug">button(@click="changeColorMode")  img(    alt="theme-icon"    :src="getDynamicFile(icon)"  )</template>

Здесь всё совсем просто! У нас есть кнопка, при клике на которую мы вызываем метод changeColorMode и меняем нашу тему. Внутри кнопки мы показываем изображение выбранной темы.

Компонент на Github.

Остается только добавить этот компонент на главную страницу нашего приложения. После этого шаблон страницы должен выглядеть так:

<template lang="pug">.page  section-header(    title="Nuxt blog"    subtitle="The best blog you can find on the global internet"  )  app-options  post-list</template>

Управление переменными


Как вы, возможно, помните из первой части, для определения всех цветов в приложении мы использовали 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.

Удалось выполнить все шаги? Как вы думаете, темная тема это просто хайп или все-таки необходимость? Делитесь мыслями в комментариях.

Ссылки на необходимые материалы:

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru