Skip to content

Compare versions

From:To:
+1~410
**Discourse, июль 2020 — февраль 2026.**

Discourse, июль 2020 — февраль 2026.

Discourse — движок форумов, на котором стоят сообщества Rust, Docker, Figma и тысячи других. Тёмная тема у него есть с 2020 года. Кнопка «переключить» — тоже.

Вопрос, на который ушло пять лет: когда человек нажимает кнопку, где записывается ответ? В браузере? В аккаунте? На устройстве? И что произойдёт, когда эти три места разойдутся.

**30 июля 2020 — Пенар делает автоматику.**

30 июля 2020 — Пенар делает автоматику.

Penar Musaraj, инженер Discourse, присылает PR #10341 «FEATURE: automatic dark mode», 1583 строки:

When the browser/OS is in dark mode using (prefers-color-scheme: dark), the dark color scheme will apply.

Когда браузер или ОС в тёмном режиме — по (prefers-color-scheme: dark) — применяется тёмная цветовая схема.

Настройка живёт у операционной системы. Сайт её только слушает. Просто и честно: никакого своего хранилища — нечему сбрасываться.

Через три недели, 27 августа, он же добавляет выбор схемы в профиле — и с первого дня ставит вопрос о месте хранения:

allows the regular/dark scheme preference to be stored in a cookie or in the user_options table (similar to theme/text size choices)

позволяет хранить выбор обычной/тёмной схемы в cookie или в таблице user_options (как выбор темы и размера текста)

Cookie для анонимных, таблица для вошедших. Правильный ответ дан в 2020-м. Дальше история о том, как его на четыре года потеряли.

**1 сентября 2020 — Джордан делает кнопку.**Changed

1 сентября 2020 — Джордан делает кнопку.

Дизайнер Jordan Vidrine заводит отдельный репозиторий Init Commit — компонент темы: кнопку в меню, которая переключает тёмную и светлую на месте, без перезагрузки. В тот же день кнопка уже работает и запоминает выбор:

js
1localStorage.setItem('userToggledScheme', 'dark')

(строки 17–29)

Компонент темы — это код, который живёт в браузере. Сервер о нажатии не узнаёт, аккаунт тоже.

Через три недели, 21 сентября, Джордан меняет хранилище: Refactor + Add cookie functionality, ключ userSelectedScheme. Cookie сервер прочитать может — но в 2020-м её на сервере не читает никто: строка forced_color_mode появится в ядре только через четыре с половиной года.

Кнопку ставят себе тысячи форумов. Она работает.

**2 декабря 2022 — настройка возвращается в браузер.**Added

2 декабря 2022 — настройка возвращается в браузер.

Пенар присылает в компонент PR #15 «REFACTOR: Use single-button toggle». Три пункта из списка в описании:

  • uses only one icon
  • switches to using local storage instead of cookies
  • resets saved override when OS dark mode matches color scheme, so for example if OS is in dark mode and the toggle switches the site to dark as well, the override is reset (essentially reverting back to auto)

— одна иконка вместо нескольких; — переходим с cookie на localStorage; — сохранённый выбор сбрасывается, когда системный тёмный режим совпадает с цветовой схемой: если ОС тёмная и переключатель тоже сделал сайт тёмным, выбор сбрасывается (то есть возвращается «авто»).

Cookie заменена на localStorage, COLOR_SCHEME_OVERRIDE_KEY = "color_scheme_override". И сброс — не побочный эффект, а объявленная возможность: настройка стирается намеренно, чтобы «авто» не расходилось с системой.

**27 декабря 2022 — Пенар описывает трещину.**Changed

27 декабря 2022 — Пенар описывает трещину.

Через двадцать пять дней, в теме поддержки компонента, Пенар отвечает на вопрос и, между делом, фиксирует то же поведение — уже как неудобство:

now the dark/light mode toggler respects the OS dark mode setting. If a user toggles their OS appearance, this component's setting is reset.

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

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

**13 февраля 2023 — приходят пользователи.**Changed

13 февраля 2023 — приходят пользователи.

Через два месяца после того рефакторинга приходят те, ради кого кнопка ставилась. jrgong, администратор форума:

Our users reported that after switching to dark mode manually, the forum switches back to light mode automatically once the device goes back to light mode. […] Expected behavior is that forum stays in dark mode due to users choice of manually switching

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

В тот же день — Kris (awesomerobot), дизайнер Discourse, и это ключевой кадр всей истории:

I guess the colors are switched on the client side, but it looks like user settings are left untouched? Is it possible to maybe update the user "color scheme" preference on toggle to avoid this? The client-side switch can provide the seamless transition, and changing the user preference can avoid the brief flash of the opposing color scheme on refresh?

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

Крис не просит починить симптом. Он называет причину — настройка живёт не там — и описывает решение целиком: клиент для мгновенности, сервер для памяти. Оно и будет реализовано. Через два года.

**20 сентября 2023 — Сара задаёт вопрос из одной строки.**Moved

20 сентября 2023 — Сара задаёт вопрос из одной строки.

Sarah Jane Obligar:

Hi, can I make the dark mode the default color? Because, whenever I log in it will switch back to light mode.

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

Ей отвечает Jakke Flemming (Jagster), администратор из сообщества: посмотрите в настройках профиля. Совет верный — и он же доказывает разрыв: кнопка и профиль не знают друг о друге, и человек должен выставить одно и то же в двух местах.

Год спустя, 11 декабря 2024, тот же Jagster на тот же вопрос от следующего человека:

It is always good policy to respect user's choises

Уважать выбор пользователя — всегда правильная политика.

За четыре года в теме — 143 сообщения. Половина из них про одно и то же.

**7 февраля 2025 — Осама переносит настройку на сервер.**Moved

7 февраля 2025 — Осама переносит настройку на сервер.

Osama Sayegh, инженер Discourse, вливает PR #31086 «FEATURE: Dark/light mode selector» — 30 файлов, +1065/−111:

This PR makes the color-scheme-toggle theme component a core feature with improvements and bug fixes. […] the color mode selector has a new "Auto" option […] the splash screen respects the color mode selected by the user

Этот PR делает компонент переключателя частью ядра, с улучшениями и исправлениями. […] у переключателя появляется вариант «Авто» […] заставка уважает выбранный режим

Главное изменение не в списке, а в устройстве: localStorage заменён на cookie forced_color_mode. Cookie читает сервер. Значит, страницу можно сразу нарисовать нужного цвета — и вспышка, о которой Крис писал два года назад, исчезает. В тот же день компонент Джордана объявлен устаревшим:

This theme component has been folded into Discourse core

Компонент влит в ядро Discourse

Настройка переехала из браузера на границу с сервером. Но не в аккаунт.

**31 июля 2025 — и наконец в аккаунт.**Moved

31 июля 2025 — и наконец в аккаунт.

Ещё через полгода Осама присылает PR #33875 «FEATURE: Color mode preference»:

it also allows setting the default mode for the user that gets used when the user logs in on a new device. It remains possible to set a color mode per device

ещё это позволяет задать режим по умолчанию для пользователя — он применится при входе с нового устройства. Задать режим для отдельного устройства по-прежнему можно

user_options.interface_color_mode. Вопрос Сары из одной строки закрыт: тёмная по умолчанию, на любом устройстве, при любом входе. Вопрос Криса — тоже: переключатель пишет и на клиент, и в профиль.

И развилка, которую здесь решили явно: настройка аккаунта и настройка устройства — разные вещи. Обе нужны. Аккаунт — умолчание; устройство — уточнение. Cookie сильнее таблицы, потому что человек мог намеренно сделать телефон тёмным, а компьютер светлым.

**Хвост.**Moved

Хвост.

Дальше идёт то, что бывает, когда настройка наконец живёт в правильном месте, — её начинают доделывать со всех сторон.

12 августа 2025Krzysztof Kotlarek убирает отдельную галочку тёмного режима из профиля: два органа управления одним и тем же — лишний.

10 октября 2025Kris (awesomerobot), семь строк:

Currently this color mode switcher has no accessible label or title, this adds both!

Сейчас у переключателя нет ни доступной подписи, ни title — добавляю обе!

9 января 2026Régis Hanol (ZogStriP), сооснователь Discourse, находит, что серверные страницы — 404, сброс пароля, приглашения — всё ещё берут логотип по системной теме:

the <source> media query was hardcoded to (prefers-color-scheme: dark), ignoring the forced_color_mode cookie.

media-запрос в <source> был зашит как (prefers-color-scheme: dark) и не учитывал cookie forced_color_mode.

Это не баг переключателя. Это старый ответ 2020 года — «слушать систему», — переживший в одном месте все четыре переезда.

**Здесь нет виноватых, и это важнее всего.**Changed

Здесь нет виноватых, и это важнее всего.

Пенар в 2020-м дал верный ответ про хранение — для того, что тогда было: выбор схемы в профиле. Джордан в 2020-м пробовал обе двери: localStorage, через три недели cookie. Разницы не вышло — cookie сервер прочитать может, но читать её было некому: компонент темы не заставит ядро рисовать страницу иначе. Пенар в 2022-м вернул localStorage и в том же PR объявил сброс возможностью, а через двадцать пять дней сам записал, как это выглядит со стороны человека. Крис в 2023-м увидел причину, но перенос компонента в ядро — это +1065 строк и 30 файлов, ради кнопки, которая «и так работает». Осама сделал это, когда сошлись «Авто», заставка, логотипы категорий — когда переезд стал оправдан не одной жалобой, а десятком.

А 143 сообщения в теме — это люди, которые по одному обнаруживали, что их выбор не запомнили, и каждому по одному объясняли, где лежит вторая настройка.

Хранить настройку человека у человекаMoved

Выписать всё, что интерфейс запоминает про пользователя (тема, шрифт, язык, свёрнутые панели), и по каждому ответить: это про человека или про устройство? Первое — в аккаунт, второе — в cookie или localStorage.

Сделать cookie копией для сервера, а не хранилищемMoved

Если страницу рисует сервер, ему нужно знать тему до первого байта. Cookie для этого; пишет её только сервер, читается она, когда аккаунта нет.

Решить явно: аккаунт против устройстваRecommendedMoved

Записать в одном месте, кто сильнее, когда аккаунт и устройство спорят. У Discourse сильнее устройство; у нас — аккаунт, и это осознанный выбор для портала, где у каждого один телефон и один компьютер.

Перенести старые ключи, а не броситьMoved

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

Подписать кнопки, у которых только иконкаRecommendedMoved

Пройти по проекту: элементы без текста внутри — с aria-label и title. Дешевле всего сделать подпись обязательной по типу в общем компоненте.

Кнопка переключения темы — самая простая вещь в интерфейсе. Нажал — стало тёмным.Moved

Кнопка переключения темы — самая простая вещь в интерфейсе. Нажал — стало тёмным.

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