Подробное руководство по темному режиму на сайте

alexei05/12/2021 - 09:09
Подробное руководство по темному режиму на сайте

Темный режим в последнее время приобрел большую популярность. Так, например, компания Apple добавила темный режим в свои операционные системы iOS и macOS. Windows и Google сделали то же самое.

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

Переключение между темами

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

Для этого существует несколько подходов.

Использование специального класса в теге body

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


<body class="dark-theme || light-theme">

Пример кода JavaScript, который будет менять класс при нажатии на специальную кнопку:


// Находим нужную кнопку
const btn = document.querySelector('.btn-toggle');

// Прослушиваем нажатие на кнопку
btn.addEventListener('click', function() {
  // Переключаем (добавляем/удаляем) класс .dark-theme
  document.body.classList.toggle('dark-theme');  
})

Вот как можно использовать эту идею:


<body>
  <button class="btn-toggle">Вкл/Выкл темный режим</button>
  <h1>Привет! Это заголовок</h1>
  <p>Это просто текст, нужный для создания абзаца</p>
  <p>А это еще один кусочек текста, потому что два лучше, чем один</p>
  <a href="#">Я ссылка.</a>
</body>

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

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


body {
  color: #222;
  background: #fff;
}

a {
  color: #0033cc;
}

У нас есть темный текст (#222) и темные ссылки (#0033cc) на светлом фоне (#fff). Наша тема "по умолчанию" успешно стартовала.

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


body {
  color: #222;
  background: #fff;
}

a {
  color: #0033cc;
}

/* Стили "темного" режима */
body.dark-theme {
  color: #eee;
  background: #121212;
}

body.dark-theme a {
  color: #809fff;
}

Стили темной темы будут производными от одного и того же родительского класса - в нашем примере это класс .dark-theme, который мы установили для элемента body.

Как же будут "переключаться" классы в элементе body, чтобы задействовать темные стили? Для этого мы будем использовать JavaScript! Мы по классу выберем кнопку переключения стилей (.btn-toggle), прикрепим к ней перехватчик событий, который будет перехватывать нажатия на нее, и по этому событию будем добавлять класс темной темы (.dark-theme) в список классов элемента body. Благодаря спецификации каскадной таблицы стилей, это будет переопределять все светлые цвета, которые мы задали по умолчанию.

Вот работающий пример. Нажмите на кнопку, чтобы включить/выключить темный режим:

Использование отдельных таблиц стилей

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

Например, стили светлой темы по умолчанию в файле light-theme.css:


/* light-theme.css */
body {
  color: #222;
  background: #fff;
}

a {
  color: #0033cc;
}

Затем мы создаем отдельные стили для темной темы и сохраняем их в отдельном файле dark-theme.css:


/* dark-theme.css */
body {
  color: #eee;
  background: #121212;
}

body a {
  color: #809fff;
}

В результате мы получаем две отдельные таблицы стилей - по одной для каждой темы - которые мы можем подключать в HTML разделе <head>. Cначала мы подключим стили светлой темы, так как мы используем их по умолчанию.


<!DOCTYPE html>
<html lang="ru">
<head>
  <!-- Стили светлой темы -->
  <link href="light-theme.css" rel="stylesheet" id="theme-link">
</head>

<!-- прочий код -->

</html>

Мы используем идентификатор #theme-link, который выбираем при помощи JavaScript, чтобы переключаться между светлым и темным режимами. Только на этот раз мы переключаем файлы таблиц стилей вместо классов.


// Выбираем кнопку
const btn = document.querySelector(".btn-toggle");
// Выбираем элемент link со стилями темы
const theme = document.querySelector("#theme-link");

// Ловим нажатие на кнопку
btn.addEventListener("click", function() {
  // Если в URL "ligh-theme.css"
  if (theme.getAttribute("href") == "light-theme.css") {
    // ... переключаем на "dark-theme.css"
    theme.href = "dark-theme.css";
  // Иначе...
  } else {
    // ... переключаем на "light-theme.css"
    theme.href = "light-theme.css";
  }
});

Использование пользовательских свойств

Мы также можем использовать возможности пользовательских свойств CSS для создания темной темы! Это позволит избежать необходимости писать отдельные наборы правил стилей для каждой темы, что значительно ускорит само написание стилей и значительно облегчает внесение изменений в тему, если это будет необходимо.

Здесь мы также будем использовать способ с заменой класса в теге body и использовать этот класс для перенастройки пользовательских свойств:


// Находим нужную кнопку
const btn = document.querySelector('.btn-toggle');

// Прослушиваем нажатие на кнопку
btn.addEventListener('click', function() {
  // Переключаем (добавляем/удаляем) класс .dark-theme
  document.body.classList.toggle('dark-theme');  
})

Сначала давайте определим значения по умолчанию для светлой темы как пользовательские свойства элемента body:


body {
  --text-color: #222;
  --bkg-color: #fff;
  --anchor-color: #0033cc;
}

Теперь мы можем переопределить эти значения в классе .dark-theme так же, как мы делали это в первом методе:


body.dark-theme {
  --text-color: #eee;
  --bkg-color: #121212;
  --anchor-color: #809fff;
}

Вот наши стили с использованием пользовательских свойств:


body {
  color: var(--text-color);
  background: var(--bkg-color);
}

a {
  color: var(--anchor-color);
}

Кстати, с таким же успехом мы могли бы определить наши пользовательские свойства внутри псевдосвойства :root, которое указывает на корень документа. Это абсолютно законная и даже обычная практика. В этом случае все стили по умолчанию определяются внутри :root { }, а все стили темной темы определяются внутри :root.dark-mode { }.

Использование серверных скриптов

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


<?php
$themeClass = '';
if (isset($_GET['theme']) && $_GET['theme'] == 'dark') {
  $themeClass = 'dark-theme';
}

$themeToggle = ($themeClass == 'dark-theme') ? 'light' : 'dark';
?>

<!DOCTYPE html>
<html lang="ru">
<!-- прочий код -->
<body class="<?php echo $themeClass; ?>">
  <a href="?theme=<?php echo $themeToggle; ?>">Вкл/Выкл темный режим</a>
  <!-- прочий код -->
</body>
</html>

Мы можем использовать запрос GET или POST, получаемый от пользователя. После этого, код (в данном случае на PHP) при перезагрузке страницы применяет соответствующий класс в элементе body. В нашем примере мы используем запрос GET (параметры URL).

И конечно же мы можем переключать таблицы стилей.


<?php
$themeStyleSheet = 'light-theme.css';
if (isset($_GET['theme']) && $_GET['theme'] == 'dark') {
  $themeStyleSheet = 'dark-theme.css';
}

$themeToggle = ($themeStyleSheet == 'dark-theme.css') ? 'light' : 'dark';
?>

<!DOCTYPE html>
<html lang="ru">
<head>
  <!-- прочий код -->
  <link href="<?php echo $themeStyleSheet; ?>" rel="stylesheet">
</head>

<body>
  <a href="?theme=<?php echo $themeToggle; ?>">Вкл/Выкл темный режим</a>
  <!-- прочий код -->
</body>
</html>

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

Какой метод выбрать?

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

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

Темный режим на уровне операционной системы

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

Чистый CSS

В CSS есть медиа-запрос prefers-color-scheme, который можно использовать для определения предпочтений системной цветовой схемы пользователя. У него может быть три возможных значения: без предпочтений, светлый (light) и темный (dark).


@media (prefers-color-scheme: dark) {
  /* Стили темной темы */
}

@media (prefers-color-scheme: light) {
  /* Стили светлой темы */
}

Чтобы все заработало, нам нужно поместить стили темной темы внутри медиа-запроса:


@media (prefers-color-scheme: dark) {
  body {
    color: #eee;
    background: #121212;
  }

  a {
    color: #809fff;
  }
}

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

JavaScript

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


const prefersDarkScheme = window.matchMedia('(prefers-color-scheme: dark)');

if (prefersDarkScheme.matches) {
  document.body.classList.add('dark-theme');
} else {
  document.body.classList.remove('dark-theme');
}

Но у метода с JavaScript есть существенный недостаток: скорее всего, на экране мельком мигнет светлая тема сайта, поскольку JavaScript выполняется после CSS — так называемый "эффект мигания неправильной темы". Это может быть неправильно истолковано как баг.

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

Переопределение параметров операционной системы

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

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


/* Цвета по умолчанию */
body {
  --text-color: #222;
  --bkg-color: #fff;
}
/* Цвета темной темы */
body.dark-theme {
  --text-color: #eee;
  --bkg-color: #121212;
}

/* Стили для включения темного режима на уровне ОС */
@media (prefers-color-scheme: dark) {
  /* темная тема по умолчанию */
  body { 
    --text-color: #eee;
    --bkg-color: #121212;
  }
  /* Переопределение темной темы светлыми стилями,
  если пользователь захочет переключиться */
  body.light-theme {
    --text-color: #222;
    --bkg-color: #fff;
  }
}

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


// Слушаем нажатие на кнопку
btn.addEventListener("click", function() {
  // Если в ОС установлен темный режим...
  if (prefersDarkScheme.matches) {
    // ...применяем класс .light-theme, чтобы переопределить эти стили
    document.body.classList.toggle("light-theme");
    // Иначе...
  } else {
    // ...применяем класс .dark-theme, чтобы переопределить эти светлые стили
    document.body.classList.toggle("dark-theme");
  }
});

Поддержка браузеров

Медиа-запрос prefers-color-scheme в настоящее время поддерживается всеми основными браузерами, включая Chrome 76+, Firefox 67+, Chrome Android 76+, Safari 12.5+ (13+ на iOS) и интернет-браузером Samsung. Но не поддерживается IE.

Это охватывает 80,85% пользователей.

Операционные системы, которые в настоящее время поддерживают темный режим, включают macOS (Mojave или более поздние версии), iOS (13.0+), Windows (10+) и Android (10+).

Сохранение предпочтений пользователя

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

Нам нужно каким-то образом зафиксировать этот выбор, чтобы он последовательно применялся на всем сайте и при последующих посещениях. Для этого мы можем во время переключения темы сохранять выбор пользователя в поле localStorage. Файлы cookie также отлично для этого подходят.

Давайте рассмотрим оба подхода.

Использование локального хранилища localStorage

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


// Выбираем кнопку
const btn = document.querySelector(".btn-toggle");
// Выбираем настройки темы из localStorage
const currentTheme = localStorage.getItem("theme");

// Если текущая тема в localStorage "dark"...
if (currentTheme == "dark") {
  // ...тогда используем класс .dark-theme
  document.body.classList.add("dark-theme");
}

// Слушаем нажатия на кнопку 
btn.addEventListener("click", function() {
  // Переключаем класс .dark-theme при каждом нажатии
  document.body.classList.toggle("dark-theme");
  
  // По умолчанию в настройках зададим светлую тему
  let theme = "light";
  // Если установлен класс .dark-theme...
  if (document.body.classList.contains("dark-theme")) {
    // ...тогда в настройках установим темную тему
    theme = "dark";
  }
  // Сохраняем настройки в хранилище localStorage
  localStorage.setItem("theme", theme);
});

Использование cookies на PHP

Чтобы избежать "моргания неправильной темы", мы можем использовать серверный скрипт, такой как PHP. Вместо того, чтобы сохранять предпочтения пользователя в хранилище localStorage, мы создадим файл cookie в скрипте на JavaScript и сохраним его у пользователя. Но опять же, реализовать этот подход можно только в том случае, если у вас есть возможность работать с серверным языком.


// Выбираем кнопку
const btn = document.querySelector(".btn-toggle");

// Слушаем нажатия на кнопку 
btn.addEventListener("click", function() {
  // Переключаем класс .dark-theme
  document.body.classList.toggle("dark-theme");
  
  // По умолчанию зададим светлую тему
  let theme = "light";
  // Если установлен класс .dark-theme...
  if (document.body.classList.contains("dark-theme")) {
    // ...тогда установим темную тему
    theme = "dark";
  }
  // Сохраняем выбор в cookie
  document.cookie = "theme=" + theme;
});

Теперь мы можем проверить наличие этого файла cookie и загрузить соответствующую тему, установив соответствующий класс в элементе body.


<?php
$themeClass = '';
if (!empty($_COOKIE['theme']) && $_COOKIE['theme'] == 'dark') {
  $themeClass = 'dark-theme';
}
?>

<!DOCTYPE html>
<html lang="ru">
<!-- прочий код -->
<body class="<?php echo $themeClass; ?>">
<!-- прочий код -->
</body>
</html>

А так можно сделать, используя разные таблицы стилей:


<?php
$themeStyleSheet = 'light-theme.css';
if (!empty($_COOKIE['theme']) && $_COOKIE['theme'] == 'dark') {
  $themeStyleSheet = 'dark-theme.css';
}
?>

<!DOCTYPE html>
<html lang="ru">
<head>
  <!-- прочий код -->
  <link href="<?php echo $themeStyleSheet; ?>" rel="stylesheet" id="theme-link">
</head>
<!-- прочий код -->

Если на вашем сайте есть учетные записи пользователей – вроде места для входа в систему и управления профилями, - то это также отличное место для сохранения настроек темы. Отправьте эти настройки в базу данных, где хранятся данные учетной записи пользователя. Затем, когда пользователь войдет в систему, извлеките настройки темы из базы данных и примените их с помощью PHP (или любого другого серверного сценария).

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


<?php
// Действие по входу в систему
if (!empty($_POST['login'])) {
  // прочий код

  // Если пользователь авторизовался...
  if ($loginSuccess) {
    // ... сохраним настройки темы в переменной сессии
    $_SESSION['user_theme'] = $userData['theme'];
  }
}

// Сначала возьмем переменную сессии, если она есть; иначе берем cookie
$themeChoice = $_SESSION['user_theme'] ?? $_COOKIE['theme'] ?? null;
$themeClass = '';
if ($themeChoice == 'dark') {
  $themeClass = 'dark-theme';
}
?>

<!DOCTYPE html>
<html lang="ru">
<!-- прочий код -->
<body class="<?php echo $themeClass; ?>">
<!-- прочий код -->
</body>
</html>

Здесь мы используем оператор объединения с null (??), чтобы определить, где брать настройки темы - из переменной сессии или из файла cookie. Если пользователь вошел в систему, то берется значение из переменной сессии вместо значения из файла cookie. Если же пользователь не вошел в систему или вышел из системы, то берется значение из файла cookie.

Сведем все вместе!

Давайте объединим все воедино и создадим рабочую демонстрацию, которая:

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

Использование JavaScript и локального хранилища


// Выбираем кнопку
const btn = document.querySelector(".btn-toggle");
// Проверяем темный режим на уровне OS
const prefersDarkScheme = window.matchMedia("(prefers-color-scheme: dark)");

// Получаем пользовательские настройки темы из локального хранилища
const currentTheme = localStorage.getItem("theme");
// Если в локальном хранилище темная тема...
if (currentTheme == "dark") {
  // ...переключаем класс .dark-mode у элемента body
  document.body.classList.toggle("dark-mode");
// Иначе, если в локальном хранилище светлая тема...
} else if (currentTheme == "light") {
  // ...переключаем класс .light-mode у элемента body
  document.body.classList.toggle("light-mode");
}

// Слушаем нажатия на кнопку
btn.addEventListener("click", function() {
  // Если в настройках OS темная тема и это соответствует нашему классу .dark-mode...
  if (prefersDarkScheme.matches) {
    // ...тогда переключаем класс .light-mode
    document.body.classList.toggle("light-mode");
    // ...но используем .dark-mode, если класс .light-mode уже установлен
    var theme = document.body.classList.contains("light-mode") ? "light" : "dark";
  } else {
    // Иначе, делаем то же самое, но с .dark-mode
    document.body.classList.toggle("dark-mode");
    var theme = document.body.classList.contains("dark-mode") ? "dark" : "light";
  }
  // Наконец, сохраним настройки в localStorage для последующего использования
  localStorage.setItem("theme", theme);
});

Использование PHP и cookies


<?php
$themeClass = '';
if (!empty($_COOKIE['theme'])) {
  if ($_COOKIE['theme'] == 'dark') {
    $themeClass = 'dark-theme';
  } else if ($_COOKIE['theme'] == 'light') {
    $themeClass = 'light-theme';
  }  
}
?>

<!DOCTYPE html>
<html lang="en">
<!-- прочий код -->
<body class="<?php echo $themeClass; ?>">
<!-- прочий код -->
<script>
  const btn = document.querySelector(".btn-toggle");
  const prefersDarkScheme = window.matchMedia("(prefers-color-scheme: dark)");
  
  btn.addEventListener("click", function() {
    if (prefersDarkScheme.matches) {
      document.body.classList.toggle("light-mode");
      var theme = document.body.classList.contains("light-mode") ? "light" : "dark";
    } else {
      document.body.classList.toggle("dark-mode");
      var theme = document.body.classList.contains("dark-mode") ? "dark" : "light";
    }
    document.cookie = "theme=" + theme;
  });
</script>
</body>
</html>

Некоторые замечания по дизайну

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

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

Изображения в темном режиме

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

Возможностей CSS функции filter() для этих целей вполне достаточно:


/* Применяем фильтр в элементе body */
body.dark-theme img {
  filter: brightness(.8) contrast(1.2);
}

/* Или через медиа-запрос */
@media (prefers-color-scheme: dark) {
  img {
    filter: brightness(.8) contrast(1.2);
  }
}

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


<picture>
  <!-- Используем это изображение, если установлены светлые цвета или цветовая схема не определена -->
  <source srcset="//msiter.ru/photo-light.png" media="(prefers-color-scheme: light) or (prefers-color-scheme: no-preference)">
  <!-- Используем это изображение, если установлены темные цвета -->
  <source srcset="//msiter.ru/photo-dark.png" media="(prefers-color-scheme: dark)">
</picture>

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

Тени в темном режиме

Реализация теней в темном режиме - довольно сложная задача. Если мы просто инвертируем темную тень, используя светлые цвета, то получим несуразную светлую тень на темном фоне… и это выглядит не очень эстетично.

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

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

Разные оттенки цвета создают разное восприятие глубины
Разные оттенки цвета создают разное восприятие "глубины"

Типографика в темном режиме

Проблема здесь та же, что и в случае с изображениями: мы должны сбалансировать контраст. Будете использовать слишком жирный шрифт, и получите "громкий" текст, при виде которого хотется отойти от экрана. Будете использовать слишком светлый шрифт, и будем напрягать глаза, придвигаясь к экрану, чтобы рассмотреть его поближе.

Баланс находится где-то посередине.

Иконки в темном режиме

Иконки также попадают в эту "сложную" категорию, так как по сути это нечто среднее между текстом и изображениями. Однако, если мы имеем дело с иконками в формате SVG, то мы можем изменить заливку с помощью CSS. С другой стороны, если мы используем иконки из шрифтовых наборов, то вместо этого мы можем просто изменить свойство color.


/* Иконка SVG */
body.dark-theme svg.icon path {
  fill: #efefef;
}

/* Шрифтовая иконка (для примера используем Font Awesome) */
body.dark-theme .fa {
  color: #efefef;
}

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

Цвета темного режима

Чистый белый текст на чистом черном фоне будет выглядеть неприятно. Хитрость здесь в том, чтобы использовать не совсем белый цвет для текста и не совсем черный для фона. Так, например, для фона часто рекомендуется использовать цвет с кодом #121212.

Цветовые палитры темного режима

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

Большинство вещей сводится к одному - контраст. Отсюда первый совет: прежде чем остановить свой выбор на каком-либо цвете, пропустите его через средства проверки контрастности, чтобы убедиться, что соотношение цветов соответствует рекомендациям WCAG по крайней мере для оценки AA, которая составляет коэффициент контрастности 4,5:1.

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

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

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

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

#232B32

#152028

#202945

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

Темный режим в интернете

YouTube использует метод с переменными CSS. Они определяют все свои цвета в переменных в селекторе html, в то время как цвета темного режима определены в разделе html:not(.style-scope)[dark]. Когда включен темный режим, YouTube добавляет атрибут dark="true" к тегу html. Это как раз то, что они используют для переопределения переменных, заданных в HTML.

YouTube добавляет атрибут dark=true к тегу html, когда переключается в темный режим
YouTube добавляет атрибут dark=true к тегу html, когда переключается в темный режим

В интернете подход с пользовательскими свойствами CSS, по-видимому, наиболее популярен. Он используется Dropbox Paper, Slack и Facebook.

Simplenote использует метод с заменой классов, при котором все светлые стили являются потомками класса .theme-light, а все темные стили относятся к классу .theme-dark. Когда тема переключается, к тегу body применяется соответствующий класс.

Simplenote использует два класса: .light-theme и .dark-theme
Simplenote использует два класса: .light-theme и .dark-theme

Twitter идет немного дальше и предлагает на выбор несколько тем: "По умолчанию", "Dim" и "Lights out". Тема "Dim" использует темно-синий цвет в качестве фона. При этом в теме "Lights out" используется абсолютно черный цвет.

Twitter предлагает три темы на выбор
Twitter предлагает три темы на выбор

С темным режимом или без темного режима? Что выбрать?

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

Со всем уважением к доводам против, приведем несколько причин, почему стоит добавить на сайт темный режим:

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

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