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

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

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

Почему я выбрал отдельные изображения

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

Но мне требовалось сохранить нормальный вид самой иллюстрации. Простое затемнение не превращает светлую сцену в продуманную тёмную версию. Оно затемняет всё сразу: фон, предметы, полезные детали.

Поэтому я остановился на паре изображений с одинаковым сюжетом и композицией. В светлом варианте — светлое окружение и мягкие тени, в тёмном — глубокий фон и более заметные световые акценты.

Объекты остаются на своих местах. При переключении темы меняется оформление сцены, а не содержание обложки.

Одна статья, две обложки

В WordPress у записи уже есть основное изображение — миниатюра публикации. Я сохранил этот механизм и добавил связь с альтернативной обложкой через метаданные записи.

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

Так мне не пришлось создавать копии статей или менять их адреса.

Основная обложка также сохранилась для поисковых метаданных и анонсов в каналах. Переключение двух версий работает непосредственно на сайте.

Как браузер выбирает картинку

Для вывода я использовал HTML-элемент <picture>. Он позволяет предложить браузеру несколько источников изображения, сохранив обычный <img> как основной вариант.

Внутри такой конструкции у альтернативной обложки есть свой <source>. В нём указаны доступные размеры изображения через srcset, чтобы браузер мог выбрать подходящий файл.

Но одного условия prefers-color-scheme здесь недостаточно. Оно отражает тему операционной системы, а посетитель может выбрать другое оформление на самом сайте.

Например, в системе включена тёмная тема, а в журнале вручную выбрана светлая. В этом случае обложка должна соответствовать странице.

Поэтому я связал выбор источника с фактической темой сайта. Небольшой скрипт обновляет условие у <source>, и браузер подставляет нужную версию.

Светлая, тёмная и системная тема

На сайте я оставил три режима:

  • светлый;
  • тёмный;
  • как в системе.

Они переключаются последовательными нажатиями одной кнопки. Выбор сохраняется в браузере.

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

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

Почему я отдельно проверял карточки журнала

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

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

Я учёл это в механизме переключения. Он реагирует и на изменение темы, и на добавление новых элементов с изображениями. Поэтому выбранное оформление применяется к карточкам после обновления списка.

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

Размер оказался не менее важен, чем цвет

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

В итоге я ограничил ширину обложки до 780 пикселей. На узком экране она занимает доступную ширину.

Пропорции сохраняются, высота рассчитывается автоматически. Внутри статьи изображение показывается полностью, без обрезки.

У светлой и тёмной версии одинаковое соотношение сторон, поэтому при переключении оформление меняется, а высота блока остаётся прежней.

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

Как я проверил результат

Я проверял не только внешний вид страницы, но и то, какой файл браузер действительно выбрал.

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

Отдельно я проверил:

  • ручное переключение светлой и тёмной темы;
  • работу режима «как в системе»;
  • обложки внутри статей и в карточках журнала;
  • размеры изображения после переключения.

В проверенных публикациях обложка внутри статьи занимала 780 × 520 пикселей в обеих темах. Изображение оставалось полным, без обрезки и изменения высоты блока.

Что получилось

Теперь обложка соответствует выбранной теме сайта. Мне не нужно дублировать запись или менять её содержимое ради другого оформления: обе версии связаны с одной публикацией.

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

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

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