Как добавить переключатель темного режима в React
30 марта 2022 г.Когда я переделал свой [сайт-портфолио] (https://abbeyperini.dev), я знал, что хочу немного повеселиться с дизайном, и темный и светлый режимы отвечали всем требованиям. Мне понравилось много открытий, которые я сделал во время этого проекта, но больше всего мне нравятся SVG, меняющие цвет. В этом руководстве предполагается, что вы знакомы с React, и я использую v17.0.1 и функциональные компоненты.
Сначала я создал базовый макет. Затем я собрал вместе свои темные и светлые цветовые схемы. Потребовалось немного проб и ошибок, но после тестирования всех моих комбинаций для [достаточного контраста] (https://webaim.org/resources/contrastchecker/) и экспериментов с размещением я обнаружил, что мне нужно 6 переменных CSS. Я думаю, вы могли бы сказать, что я использовал разработку «сначала темная», потому что имена переменных имеют смысл в контексте темной темы. Светлая тема имеет меньше вариаций, но требует --button-border
, где --accent
будет того же цвета, что и фон.
```javascript
.theme-темный {
--темный текст: #292929;
--light-текст: #F9F8F8;
--темный фон: #2F4550;
--светлый фон: #586F7C;
--акцент: #B8DBD9;
--button-border: #B8DBD9;
```javascript
.theme-свет {
--темный текст: #5E4B56;
--light-текст: #5E4B56;
--темный фон: #DBE7E4;
--light-background: #EDCDD2;
--акцент: #DBE7E4;
--button-border: #5E4B56;
Затем я приступил к применению цветов к моему базовому макету:
```javascript
html, #корень {
цвет фона: var(--темный-фон);
цвет: var(--темный текст);
навигация {
цвет фона: var(--темный-фон);
цвет: var(--light-text);
.основной контейнер {
цвет фона: var(--light-background);
Я также установил фон разделов контента, который я хотел выделить, на --accent
. --dark-text
работал бы на всех фонах в темной теме, но я установил для заголовков разделов значение --light-text
, чтобы они больше выделялись.
Я нашел [учебник по базовому переключению тем] от Musthaq Ahamad (https://medium.com/@haxzie/dark-and-light-theme-switcher-using-css-variables-and-pure-javascript-zocada-dd0059d72fa2) , и приступил к применению его к функциональным компонентам React. Я поместил функции для изменения темы и проверки localStorage для предпочтений темы в файл с именем themes.js
.
```javascript
функция setTheme(themeName) {
localStorage.setItem('тема', имятемы);
document.documentElement.className = темаимя;
функция keepTheme () {
если (localStorage.getItem('тема')) {
если (localStorage.getItem('тема') === 'темная тема') {
setTheme('темная тема');
} else if (localStorage.getItem('theme') === 'theme-light') {
setTheme('светлая тема')
} еще {
setTheme('темная тема')
модуль.экспорт = {
установить тему,
держать тему
В моем файле App.js
я добавил keepTheme()
к моему useEffect()
.
```javascript
импортировать {keepTheme} из './utils/themes';
приложение функции () {
использоватьЭффект(() => {
сохранить тему();
Затем я добавил компонент-переключатель к своему компоненту панели навигации. Я создал переключатель в соответствии с [учебником Криса Бонгерса] (https://h.daily-dev-tips.com/creating-day-night-css-only-toggle-switch), основанным на [Dribbble Кати Де Хуан] (https ://dribbble.com/shots/3220898-Day-Night-toggle-DailyUI-015). Затем я [отрегулировал размер и переключил его на темный режим по умолчанию] (https://github.com/abbeyperini/Portfolio2.0/blob/master/portfolio/src/styles/toggle.css). Хотя этот переключатель настолько симпатичный, что вы можете умереть, это руководство будет работать с любой <button>
или интерактивным <input>
. Во-первых, я настроил базовый JSX, локальное состояние и переменную для хранения темы, которую мы получаем из localStorage:
```javascript
импортировать React, {useEffect, useState} из 'реагировать';
импортировать '../styles/toggle.css';
импортировать {setTheme} из '../utils/themes';
функция Переключение () {
const [togClass, setTogClass] = useState('темный');
пусть тема = localStorage.getItem('тема');
вернуть (
переключатель экспорта по умолчанию;
Когда пользователь щелкает переключатель, я хочу, чтобы тема на странице менялась, а переключатель менялся вместе с ней. Я добавил импортированную функцию setTheme()
и setTogClass()
из локального состояния в функцию handleOnClick. Вы можете видеть, где он передается кликабельной части переключателя в JSX выше.
```javascript
константа handleOnClick = () => {
если (localStorage.getItem('тема') === 'темная тема') {
setTheme('светлая тема');
setTogClass («свет»)
} еще {
setTheme('темная тема');
setTogClass («темный»)
Я использовал useEffect()
этого компонента, чтобы убедиться, что togClass локального состояния всегда загружается с правильной темой.
использоватьЭффект(() => {
если (localStorage.getItem('тема') === 'темная тема') {
setTogClass («темный»)
} else if (localStorage.getItem('theme') === 'theme-light') {
setTogClass («свет»)
}, [тема])
Поскольку мой переключатель является флажком, темная тема должна показывать неотмеченное (луна) состояние, а светлая тема должна показывать отмеченное (солнце) состояние. Мне не удалось заставить defaultChecked
работать так, как я хотел, поэтому я заменил непроверенный <input>
этим условным рендерингом тернарный оператор (условный оператор ):
```javascript
togClass === "свет" ?
Если вы использовали <button>
, вы могли бы легко использовать условный рендеринг, подобный этому, чтобы изменить атрибут className в теге <button>
и получить тот же эффект.
Собрав все вместе, код компонента-переключателя выглядит так:
```javascript
импортировать React, {useEffect, useState} из 'реагировать';
импортировать '../styles/toggle.css';
импортировать {setTheme} из '../utils/themes';
функция Переключение () {
const [togClass, setTogClass] = useState('темный');
пусть тема = localStorage.getItem('тема');
константа handleOnClick = () => {
если (localStorage.getItem('тема') === 'темная тема') {
setTheme('светлая тема');
setTogClass («свет»)
} еще {
setTheme('темная тема');
setTogClass («темный»)
использоватьЭффект(() => {
если (localStorage.getItem('тема') === 'темная тема') {
setTogClass («темный»)
} else if (localStorage.getItem('theme') === 'theme-light') {
setTogClass («свет»)
}, [тема])
вернуть (
togClass === "свет" ?
Обновлять
Чтобы увидеть, как я реорганизовал логику этого компонента и сделал его доступным, прочитайте Доступный переключатель темного режима в React.
Наконец, моя любимая часть: SVG с переключением цветов! Переменные CSS работают и в коде SVG!
Я получил код SVG для значков Github и Chrome от [DEVICON] (https://devicon.dev/). Для значка Github все, что мне нужно было изменить, это один атрибут заполнения в <g>
:
```разметка
Значок Chrome имел атрибут заполнения в <circle>
и <path>
:
```разметка
Результат выглядит следующим образом:
Заключение
Я попытался включить весь соответствующий код, но вы также можете увидеть полный код моего сайта в его [репозитории Github] (https://github.com/abbeyperini/Portfolio2.0). Если вам понравилась эта статья или остались вопросы, пожалуйста, оставьте комментарий! Я также хотел бы увидеть что-нибудь построенное по этому уроку.
Также опубликовано здесь
Оригинал