Реализация темного / светлого режима в приложениях с помощью React

Как следует из названия, этот блог посвящен реализации темного / светлого режима в приложениях, использующих React. Я считаю, что вы уже знаете о светлых и темных темах в приложениях.

Светлый режим: относится к темному шрифту на светлом фоне (положительная контрастная полярность).

Темный режим: обозначает сочетание светлого (например, белого) текста на темном (например, черном) фоне (отрицательная контрастная полярность).

Эти две темы имеют некоторые преимущества и могут быть настроены как на мобильном устройстве, так и на компьютере. Мы можем изменить этот темный / светлый режим с Setting-> Display-> THEME на большинстве устройств. Или мы также можем добавить функцию переключения на веб-сайтах, чтобы явно переключаться между светлой и темной темами.

Почему это важно? Что ж, есть несколько моментов, которые делают веб-сайт лучше, когда у него есть тема темного режима:

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

Если говорить о части реализации, я использовал window.matchMedia для проверки темы prefers-color-scheme.

// EventListener when mode/theme is changed
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => {
  if (event.matches) {
    // set mode state to Dark here
  } else {
    // set mode state to Light here
  }
});

Этот код выше является слушателем, который проверяет, есть ли изменение в событии (prefers-color-scheme: dark). Итак, если системная тема темная, тогда if условие истинно, и мы можем переключить состояние режима на Dark здесь, иначе в операторе else, где мы можем переключить состояние в режим Light.

Я использовал это же событие window.matchMedia('(prefers-color-scheme: dark)'), чтобы установить состояние темы по умолчанию в моем приложении следующим образом:

// To set default value when page is refreshed
let defaultMode = 'light';
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
  defaultMode = 'dark';
}

Таким образом, если системный параметр уже установлен как Dark, тогда условие if (window.matchMedia('(prefers-color-scheme: dark)').matches) оценивается как истинное, а для приложения defaultMode устанавливается значение dark.

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

Светлая тема (изображение слева): Цвет фона: белый, Цвет текста: черный.

Темная тема (изображение справа): Цвет фона: Черный, Цвет текста: Белый.

Начните с добавления контекста в приложение.

Здесь у контекста есть две клавиши mode (значение темы: темный / светлый) и toggle ( функция для переключения режима ).

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

В этом файле мы добавляем поставщика, который использует useDarkmode и darkModeContext

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

Чтобы реализовать эту функциональность, оберните свое приложение внутри провайдера, как этот (Файл приложения):

import React from 'react';
import { object } from 'prop-types';
import DarkProvider from './darkModeProvider';
import MainComponent from './mainComponent';
function App({ history, client }) {
  return (
    <DarkProvider>
      <MainComponent />
    </DarkProvider>
  );
}
App.propTypes = {
  client: object.isRequired,
  history: object.isRequired,
};
export default App;

Если ваш MainComponent выглядит примерно так (файл mainComponent.js)

import React from 'react';
import { useDarkmodeContext } from './darkModeProvider';
import { setThemeMode } from './styles';
const MainComponent = () => {
  const { mode } = useDarkmodeContext();
  const themeMode = mode || 'light';
  const css = setThemeMode(themeMode);
return (
      <div className={css.container}>
        <div>
          <div className={css.emptySearchHeading}>
            {themeMode?.toUpperCase()} THEME
          </div>
          <div className={css.emptySearchText}>
            Demo...
          </div>
        </div>
      </div>
  );
};
export default MainComponent;

В приведенном выше файле useDarkmodeContext получает состояние режима независимо от того, светлый он или темный. Из этого состояния мы можем затем установить нашу тему в файле styles.js. Как указано ниже (файл styles.js):

import { css } from 'react-emotion';
import { Theme } from './colors';
// set colors dynamically based on the mode from Theme
// color: ${Theme[mode].blackNewRgba};
export const setThemeMode = mode => {
  return {
    container: css`
      display: flex;
      padding: 16px;
      justify-content: center;
      background: ${Theme[mode].containerColor};
    `,
    emptySearchHeading: css`
      font-size: 16px;
      color: ${Theme[mode].headingColor};
      text-align: center;
      font-weight: bold;
    `,
    emptySearchText: css`
      font-size: 12px;
      color: ${Theme[mode].textColor};
      text-align: center;
    `,
  };
};

Объект Theme содержит все варианты цвета для светлого и темного режимов. Мы можем проверить этот объектный код ниже (./colors.js).

// Base color
export const headingColor = 'rgba(49, 53, 59, 0.96)';
export const textColor = `rgba(49, 53, 59, 0.68)`;
export const containerColor = '#ffffff';
const lightTheme = {
  headingColor,
  textColor,
  containerColor,
};
const darkTheme = {
  headingColor: '#ffffff',
  textColor : '#ffffff',
  containerColor: '#000',
};
export const Theme = {
  light: lightTheme,
  dark: darkTheme,
};

Итак, из этого файла мы экспортируем объект Тема, например:

export const Theme = {
  light: lightTheme,
  dark: darkTheme,
};

Вывод

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