Обновите темы и плагины для поддержки автоматического темного режима

Ранее все цвета в Discourse хранились как переменные SCSS. Для поддержки автоматического переключения цветовой схемы в тёмном режиме мы преобразовали эти цвета в ядре в пользовательские свойства CSS. Теперь вы можете легко просмотреть полный список в инспекторе:

Темам и плагинам необходимо заменить все переменные SCSS $color, используемые в стилях, на эквивалентные пользовательские свойства CSS --color. В большинстве случаев это простая задача поиска и замены:

-   background-color: $primary-very-low;
+   background-color: var(--primary-very-low);

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

В плагинах

Этот коммит в плагине discourse-encrypt является хорошим и простым примером такой рефакторинга. Он перемещает объявление SCSS mix($color1, $color2) в отдельный файл и сохраняет его как пользовательское свойство CSS. Затем новый файл регистрируется как актив :color_definitions, что гарантирует включение вновь объявленного свойства цвета в таблицу определений цветов.

В темах

В темах вы можете сделать то же самое, объявив пользовательские свойства CSS в таблице стилей common/color_definitions.scss. Вы можете посмотреть этот коммит в теме graceful в качестве примера.

Дополнительные примечания

  • при использовании прозрачных цветов через функцию rgba($color, 0.5) SCSS принимает HEX и RGB цвета в первом параметре, тогда как пользовательские свойства CSS принимают только RGB цвета. Вот почему мы добавили вспомогательную функцию hexToRGB() и некоторые свойства с суффиксом --rgb в определениях цветов. Пример:
// color_definitions.scss
:root {
  --primary: #{$primary};
  --primary-rgb: #{hexToRGB($primary)};
}

// другой файл стилей
.element {
  background-color: rgba(var(--primary-rgb), 0.05);
}
  • обратите внимание, что в приведённом выше фрагменте переменная SCSS интерполируется при передаче в пользовательское свойство. Это требование SCSS, подробнее см. Sass: Property Declarations.
  • объявление CSS var() может использовать значение по умолчанию, если первое значение недоступно. Например, при записи var(--color1, red) CSS вернёт красный цвет, если свойство --color1 не найдено. В плагинах мы используем переменные цвета SCSS в качестве значений по умолчанию для обеспечения совместимости с предыдущими версиями Discourse. Таким образом, приведённый выше пример с значением по умолчанию будет выглядеть так:
-   background-color: $primary-very-low;
+   background-color: var(--primary-very-low, $primary-very-low);

Этот документ находится под версионным контролем — предложите изменения на GitHub.

24 лайка

Я не очень разбираюсь в этом, и мне потребуется время, чтобы разобраться самостоятельно. . . Это значит, что все темы, которые ранее ссылались на цвета, теперь будут сломаны?

6 лайков

Нет, вовсе нет. SCSS-переменные в темах продолжат работать еще долгое время.

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

13 лайков

Спасибо за инструкции. Можно ли также менять фоновое изображение в зависимости от тёмного/светлого режима? (Я использовал компонент переключателя темы для этого.) Возможно ли использовать CSS-класс, указывающий на текущий режим?

2 лайка

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

Итак, если у вас в теме или компоненте темы есть два изображения с SCSS-переменными $bg-light и $bg-dark соответственно, вы можете добавить следующее в ваш файл стилей color_definitions.scss:


$bg: url(dark-light-choose($bg-light, $bg-dark));

:root {
  --custom-bg: #{$bg};
}

А затем вы можете использовать var(--custom-bg) в вашем обычном файле стилей.

8 лайков

Для изображения достаточно использовать стандартный CSS-медиазапрос prefers-dark-theme.

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

4 лайка

Возможно ли, чтобы Discourse также добавлял CSS-класс к тегу <body> для цветовой схемы или её идентификатора? Это, казалось бы, значительно упростило бы задачу.

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

Если бы я мог просто сделать что-то вроде этого в изолированном SCSS-файле в теме, то на то, что сейчас занимает много времени на разбирательство с color_definitions.scss, ушло бы всего 5 минут:

body.dark-palette .some-thing {
  // какие-то стили
}

body.light-palette .some-thing {
  // какие-то стили
}

Возможно, я не понимаю наилучший способ сделать это, но кажется, что для каждой переменной приходится выполнять множество действий — настройка одной CSS-переменной занимает 17 строк в редакторе далеко от того небольшого места, где она будет использоваться:

  • определение значения светлого режима в SCSS-переменной (это может занимать 6 строк в редакторе для чего-то вроде линейного градиента);
  • определение значения темного режима в SCSS-переменной (еще 6 строк);
  • определение SCSS-переменной с использованием dark-light-choose (4 строки из-за длинных имен переменных);
  • присвоение этой последней SCSS-переменной CSS-переменной в :root (1 строка).

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

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

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

Альтернативой может быть использование чего-то подобного:

@container style(--scheme-type: light){
  body{
    background: red;
  }
}

Наши цветовые схемы включают свойство --scheme-type, которое равно light для светлых схем и dark для тёмных. Современные браузеры поддерживают запросы к контейнерам, поэтому этот подход позволит решить вашу задачу без добавления класса к тегу body на странице.

Мои навыки работы с CSS/SCSS не очень хороши. Возможно, это проще для тех, кто глубоко погружён в эти технологии.

Это приводило к беспорядку в файле color_definitions.scss, поэтому я переместил его в другой файл в папке scss/, чтобы иметь возможность его импортировать. Я не уверен, как лучше всё назвать, поэтому сейчас это выглядит так.

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

Обратите внимание, что на сегодняшний день (14.11.2025) запросы стилей для пользовательских свойств не работают в Firefox (1795622 - (container-style-queries) [css-contain-3] [meta] Support style() container queries).