[CSS, JavaScript, ReactJS, TypeScript] Темизация. История, причины, реализация
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Введение. Причины появленияКогда веб только зарождался – единственной его целью было размещение контента (гипертекстовые страницы), чтобы у пользователей из всемирной паутины был к нему доступ. В то время не могло идти и речи о дизайне, ведь зачем нужен дизайн страницам с научными публикациями, разве они станут от этого полезнее (первый сайт). Времена меняются и сегодня во всемирной паутине далеко не только научные публикации. Блоги, сервисы, социальные сети и многое, многое другое. Каждый сайт нуждается в своей индивидуальности, ему необходимо заинтересовывать и привлекать пользователей. Даже научные сайты постепенно это понимают, ведь большинство ученых хотят не просто изучать те или иные аспекты, а доносить их до людей, тем самым повышая свою популярность и ценность своих исследований (пример – 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”.Основные шаги при темизации сайта:
- Создание стилей каждой темы (цвета, тени, рамки);
- Настройка темы по умолчанию, в зависимости от темы устройства пользователя (в случае с темной и светлой темой);
- Настройка манифеста и мета тегов;
- Создание стилизованных компонентов;
- Настройка смены темы при нажатии на кнопку;
- Сохранение выбранной темы на устройстве пользователя.
Третий шаг универсален для любого варианта темизации. Поэтому, сперва кратко о нем.Манифест – это файл, используемый, в первую очередь, для PWA. Однако, его содержимое является альтернативой метатегам и загружается быстрее них. В случае темизации нас интересуют такие ключи, как «theme_color» и «background_color». Мети-теги с этими параметрами также можно добавить в head страницы.Theme_color – цвет темы сайта. Указанный цвет будет использоваться в качестве цвета вкладки и строки состояния на мобильных устройствах на системе Android. У данного функционала крайне скудная поддержка браузеров, однако доля этих браузеров составляет 67%.
caniuse.comBackground_color – цвет, который будет загружаться до загрузки стилей. Поддержка данного атрибута еще более скудная, чем у цвета темы:
caniuse.comПеременныеНачать описание этого варианта стоит с поддержки, так как это, пожалуй, его единственный минус.
caniuse.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. Продолжать список можно бесконечно, несмотря на то, что это только начало развития технологии, а дальше – больше, лучше и проще.
===========
Источник:
habr.com
===========
Похожие новости:
- [Программирование, TypeScript] Карманная книга по TypeScript. Часть 7. Классы (перевод)
- [Разработка веб-сайтов, JavaScript, Карьера в IT-индустрии, IT-компании] Как я попал на стажировку в Яндекс
- [JavaScript, Программирование, Разработка систем связи, Облачные сервисы] Скрываем номера курьеров и клиентов с помощью key-value хранилища
- [Настройка Linux, Open source, Виртуализация, Kubernetes] Изучение экоcистемы Kubernetes в 2021 году, global modal в React и 7 сетевых команд Linux для каждого сисадмина
- [JavaScript, Разработка игр] SpaceShooter на Phaser 3
- [Разработка веб-сайтов, CSS, HTML] DIV должен уйти: улучшаем HTML (перевод)
- [Тестирование IT-систем, PHP, Программирование] «Дело было вечером, делать было нечего» или краткая история о сравнении производительности языков программирования
- [JavaScript, ReactJS] React. Не в глубь, а в ширь. Композиция против реальности
- [JavaScript, Google Chrome, API, Расширения для браузеров, Реверс-инжиниринг] Как я доделал функции за Яндекс.Музыкой
- [JavaScript, Node.JS] Как работает Middleware в Express?
Теги для поиска: #_css, #_javascript, #_reactjs, #_typescript, #_temizatsija (темизация), #_styledcomponents, #_dark_mode, #_night_theme, #_nochnoj_rezhim (ночной режим), #_css_variables, #_css3, #_react, #_typescript, #_css, #_javascript, #_reactjs, #_typescript
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 25-Ноя 05:21
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Введение. Причины появленияКогда веб только зарождался – единственной его целью было размещение контента (гипертекстовые страницы), чтобы у пользователей из всемирной паутины был к нему доступ. В то время не могло идти и речи о дизайне, ведь зачем нужен дизайн страницам с научными публикациями, разве они станут от этого полезнее (первый сайт). Времена меняются и сегодня во всемирной паутине далеко не только научные публикации. Блоги, сервисы, социальные сети и многое, многое другое. Каждый сайт нуждается в своей индивидуальности, ему необходимо заинтересовывать и привлекать пользователей. Даже научные сайты постепенно это понимают, ведь большинство ученых хотят не просто изучать те или иные аспекты, а доносить их до людей, тем самым повышая свою популярность и ценность своих исследований (пример – 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); } :root {
--header-color: #06c; } h1 { background-color: var(--header-color); } В параллель спецификации 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', }, },
caniuse.comBackground_color – цвет, который будет загружаться до загрузки стилей. Поддержка данного атрибута еще более скудная, чем у цвета темы: caniuse.comПеременныеНачать описание этого варианта стоит с поддержки, так как это, пожалуй, его единственный минус. caniuse.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; } @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; } }
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') } });
.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 {
display: flex; align-items: center; padding: 8px 0; color: var(--text-lvl9-color); background-color: var(--shared-primary-color); }
body.classlist.remove('theme-light', 'theme-high')
body.classlist.add('theme-dark')
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}`) } 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> ) } 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') } }) }, []) 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 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 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> ) } 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 ...
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 ( ... ) } =========== Источник: habr.com =========== Похожие новости:
|
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 25-Ноя 05:21
Часовой пояс: UTC + 5