Найти в Дзене
in9var

Добавляем тёмную тему на сайт Next.js: пример простой реализации

Привет! Сегодня покажу, как за несколько минут с помощью готовой библиотеки реализовать переключение между темной и светлой темой на сайте. Выбранная тема сохраняется в localStorage браузера и отлично работает на всех устройствах. Код данной статьи доступен в репозитории GitHub по ссылке. Вводим команду в консоль: npm i next-themes Данный пакет сильно упрощает реализацию переключения тем: он берет на себя все заботы о хранении выбранной темы и решает такие проблемы, как «вспышки» при обновлении страницы с выбранной темной темой. Если вы решите реализовывать переключение тем самостоятельно, вы поймете, о чем я. В папке app/theme создаем файл theme-provider.tsx со следующим содержимым: 'use client'; import { ThemeProvider as NextThemesProvider } from 'next-themes'; export function ThemeProvider({ children, ...props }) { return <NextThemesProvider {...props}>{children}</NextThemesProvider>; } Этот кусок кода взят из официальной документации. В папке app/components создадим файл ThemeSwit
Оглавление

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

Превью | Канал dzen.ru/in9var
Превью | Канал dzen.ru/in9var

Код данной статьи доступен в репозитории GitHub по ссылке.

Устанавливаем пакет next-themes

Вводим команду в консоль:

npm i next-themes

Данный пакет сильно упрощает реализацию переключения тем: он берет на себя все заботы о хранении выбранной темы и решает такие проблемы, как «вспышки» при обновлении страницы с выбранной темной темой.

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

Создаем провайдер темы

В папке app/theme создаем файл theme-provider.tsx со следующим содержимым:

'use client';
import { ThemeProvider as NextThemesProvider } from 'next-themes';
export function ThemeProvider({ children, ...props }) {
return <NextThemesProvider {...props}>{children}</NextThemesProvider>;
}

Этот кусок кода взят из официальной документации.

Создаем переключатель темы

В папке app/components создадим файл ThemeSwitcher.jsx со следующим содержимым:

'use client';
import { useEffect, useState } from 'react';
import { useTheme } from 'next-themes';
import { FaSun, FaMoon } from 'react-icons/fa';
const ThemeSwitcher = () => {
const [mounted, setMounted] = useState(false);
const { theme, setTheme } = useTheme();
const handleClick = () => {
if (theme === 'light') setTheme('dark');
else setTheme('light');
};
useEffect(() => {
setMounted(true);
}, [theme]);
if (!mounted) return null;
return (
<button
type='button'
onClick={handleClick}
className={`cursor-pointer rounded-md p-2 border-2 ${theme === 'light' ? 'border-primary' : 'border-secondary'}`}
>
{theme === 'light' ? (
<FaSun size={28} className='text-primary' />
) : (
<FaMoon size={28} className='text-secondary' />
)}
</button>
);
};
export default ThemeSwitcher;

Используя встроенный в библиотеку next-themes кастомный хук useTheme(), мы сможем управлять переключением темы, а также контролировать текущую тему. Создадим кнопку button, которая меняет иконку в зависимости от выбранной темы, а при нажатии переключает тему на противоположную.

Подключаем провайдер в layout.jsx

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

Код layout.jsx:

import { Geist, Geist_Mono } from 'next/font/google';
import './globals.css';
import { ThemeProvider } from './theme/theme-provider';
import ThemeSwitcher from './components/ThemeSwitcher';
const geistSans = Geist({
variable: '--font-geist-sans',
subsets: ['latin'],
});
const geistMono = Geist_Mono({
variable: '--font-geist-mono',
subsets: ['latin'],
});
export const metadata = {
title: 'Create Next App',
description: 'Generated by create next app',
};
export default function RootLayout({ children }) {
return (
<html lang='ru' suppressHydrationWarning>
<body className={`${geistSans.variable} ${geistMono.variable} antialiased`}>
<ThemeProvider attribute='data-mode' defaultTheme='light'>
<header className='flex justify-end w-full px-5 mx-auto max-w-screen-xl py-4'>
<ThemeSwitcher />
</header>
{children}
</ThemeProvider>
</body>
</html>
);
}

Как это работает?

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

<html lang="ru" data-mode="light" style="color-scheme: light;">

В нашем случае мы задаем цвета темы через переменные, и за счет атрибута [data-mode] сайт перекрашивается в соответствующие выбранной теме цвета.

:root {
--color-primary: 270 80% 20%;
--color-secondary: 47 80% 50%;
--color-on-primary: 260 9% 13%;
--color-on-secondary: 260 9% 13%;
}
[data-mode='light'] {
--color-background: 0 0% 100%;
--color-on-background: 0 0% 0%;
}
[data-mode='dark'] {
--color-background: 0 0% 0%;
--color-on-background: 0 0% 100%;
}

В итоге получаем рабочую кнопку переключения тем:

-2
-3
-4
-5

Данная статья и весь код в удобном формате доступны по ссылке.

На этом всё, если появятся вопросы, пишите их в комменты, постараюсь на них ответить.

Не забудь подписаться на канал, а также заходи на мой блог blog.in9var.ru, а также можешь посетить мой основной сайт — in9var.ru.