Skip to content

Compare versions

From:To:
+287
11¶ **Discourse, июль 2020 — февраль 2026.**
22
33 Discourse — движок форумов, на котором стоят сообщества Rust, Docker, Figma и тысячи других. Тёмная тема у него есть с 2020 года. Кнопка «переключить» — тоже.
44
55 Вопрос, на который ушло пять лет: **когда человек нажимает кнопку, где записывается ответ?** В браузере? В аккаунте? На устройстве? И что произойдёт, когда эти три места разойдутся.
66¶ **30 июля 2020 — Пенар делает автоматику.**
77
88 [Penar Musaraj](https://github.com/pmusaraj), инженер Discourse, присылает [PR #10341](https://github.com/discourse/discourse/pull/10341) «FEATURE: automatic dark mode», 1583 строки:
99
1010 > When the browser/OS is in dark mode using `(prefers-color-scheme: dark)`, the dark color scheme will apply.
1111 >
1212 > *Когда браузер или ОС в тёмном режиме — по `(prefers-color-scheme: dark)` — применяется тёмная цветовая схема.*
1313
1414 Настройка живёт у операционной системы. Сайт её только слушает. Просто и честно: никакого своего хранилища — нечему сбрасываться.
1515
1616 Через три недели, [27 августа](https://github.com/discourse/discourse/pull/10544), он же добавляет выбор схемы в профиле — и с первого дня ставит вопрос о месте хранения:
1717
1818 > allows the regular/dark scheme preference to be stored in a cookie or in the `user_options` table (similar to theme/text size choices)
1919 >
2020 > *позволяет хранить выбор обычной/тёмной схемы в cookie или в таблице `user_options` (как выбор темы и размера текста)*
2121
2222 Cookie для анонимных, таблица для вошедших. Правильный ответ дан в 2020-м. Дальше история о том, как его на четыре года потеряли.
23**4 сентября 2020 — Джордан делает кнопку.**
23+**1 сентября 2020 — Джордан делает кнопку.**
2424
25 Дизайнер [Jordan Vidrine](https://github.com/jordanvidrine) собирает [компонент темы](https://github.com/discourse/discourse-color-scheme-toggle/commit/3d2796a2feb5832ddbbb1bf005f8669f04a14ee0) — кнопку в меню, которая переключает тёмную и светлую на месте, без перезагрузки.
25+ Дизайнер [Jordan Vidrine](https://github.com/jordanvidrine) заводит отдельный репозиторий [`Init Commit`](https://github.com/discourse/discourse-color-scheme-toggle/commit/6982b433dd2b70a8ef1b6e9d38e72766061bafbf) компонент темы: кнопку в меню, которая переключает тёмную и светлую на месте, без перезагрузки. В тот же день кнопка уже [работает](https://github.com/discourse/discourse-color-scheme-toggle/commit/f1d2a0c8a7ab24844cd06c367a3ab5d450b0e9b5) и запоминает выбор:
2626
27 Компонент темы — это код, который живёт в браузере и на сервер не ходит. Поэтому свой выбор он запоминает единственно доступным способом: в localStorage, ключ `color_scheme_override`. Аккаунт о нажатии не узнаёт.
27+ ```js
28+ localStorage.setItem('userToggledScheme', 'dark')
29+ ```
2830
31+ ([строки 17–29](https://github.com/discourse/discourse-color-scheme-toggle/blob/f1d2a0c8a7ab24844cd06c367a3ab5d450b0e9b5/javascripts/discourse/initializers/dark-light-toggle.js#L17-L29))
32+
33+ Компонент темы — это код, который живёт в браузере. Сервер о нажатии не узнаёт, аккаунт тоже.
34+
35+ Через три недели, [21 сентября](https://github.com/discourse/discourse-color-scheme-toggle/commit/a4f11157fbe1e211a7f77ea4dba53b76b3c360c7), Джордан меняет хранилище: `Refactor + Add cookie functionality`, ключ `userSelectedScheme`. Cookie сервер прочитать может — но в 2020-м её на сервере не читает никто: строка `forced_color_mode` появится в ядре только через четыре с половиной года.
36+
2937 Кнопку ставят себе тысячи форумов. Она работает.
38+¶ **2 декабря 2022 — настройка возвращается в браузер.**
39+
40+ Пенар присылает в компонент [PR #15](https://github.com/discourse/discourse-color-scheme-toggle/pull/15) «REFACTOR: Use single-button toggle». Три пункта из списка в описании:
41+
42+ > - uses only one icon
43+ > - switches to using local storage instead of cookies
44+ > - 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)
45+ >
46+ > *— одна иконка вместо нескольких;*
47+ > *— переходим с cookie на localStorage;*
48+ > *— сохранённый выбор сбрасывается, когда системный тёмный режим совпадает с цветовой схемой: если ОС тёмная и переключатель тоже сделал сайт тёмным, выбор сбрасывается (то есть возвращается «авто»).*
49+
50+ Cookie заменена на localStorage, [`COLOR_SCHEME_OVERRIDE_KEY = "color_scheme_override"`](https://github.com/discourse/discourse-color-scheme-toggle/commit/cd2210063bb01109a8d1aecf6d60c42d88429a29). И сброс — не побочный эффект, а объявленная возможность: настройка стирается намеренно, чтобы «авто» не расходилось с системой.
3051¶ **27 декабря 2022 — Пенар описывает трещину.**
3152
32 В [теме поддержки компонента](https://meta.discourse.org/t/dark-light-mode-toggle/215585/62) Пенар отвечает на вопрос и, между делом, фиксирует поведение:
53+ Через двадцать пять дней, в [теме поддержки компонента](https://meta.discourse.org/t/dark-light-mode-toggle/215585/62), Пенар отвечает на вопрос и, между делом, фиксирует то же поведение — уже как неудобство:
3354
3455 > 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.
3556 >
3657 > *теперь переключатель уважает системную настройку. Если пользователь меняет оформление ОС, настройка компонента сбрасывается.*
3758
38 Два хозяина у одной настройки: система и localStorage. Когда они спорят, побеждает система, и выбор человека стирается. Пока это выглядит как допустимая мелочь.
59+ Два хозяина у одной настройки: система и localStorage. Когда они спорят, побеждает система, и выбор человека стирается. Пока это выглядит как допустимая мелочь — так и было задумано месяцем раньше.
3960¶ **13 февраля 2023 — приходят пользователи.**
4061
41 [jrgong](https://meta.discourse.org/t/dark-light-mode-toggle/215585/79), администратор форума:
62+ Через два месяца после того рефакторинга приходят те, ради кого кнопка ставилась. [jrgong](https://meta.discourse.org/t/dark-light-mode-toggle/215585/79), администратор форума:
4263
4364 > 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
4465 >
4566 > *Наши пользователи сообщают: после ручного включения тёмной темы форум сам возвращается к светлой, как только устройство переходит в светлый режим. […] Ожидается, что форум останется тёмным — человек выбрал это сам.*
4667
4768 В тот же день — [Kris (awesomerobot)](https://meta.discourse.org/t/dark-light-mode-toggle/215585/81), дизайнер Discourse, и это ключевой кадр всей истории:
4869
4970 > 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?
5071 >
5172 > *Похоже, цвета переключаются на клиенте, а настройки пользователя не трогаются? Нельзя ли при нажатии обновлять и «цветовую схему» в профиле? Клиент даёт плавный переход, а запись в профиль уберёт вспышку противоположной схемы при перезагрузке.*
5273
5374 Крис не просит починить симптом. Он называет причину — настройка живёт не там — и описывает решение целиком: клиент для мгновенности, сервер для памяти. Оно и будет реализовано. Через два года.
5475¶ **20 сентября 2023 — Сара задаёт вопрос из одной строки.**
5576
5677 [Sarah Jane Obligar](https://meta.discourse.org/t/dark-light-mode-toggle/215585/115):
5778
5879 > Hi, can I make the dark mode the default color? Because, whenever I log in it will switch back to light mode.
5980 >
6081 > *Здравствуйте, можно сделать тёмную тему по умолчанию? Потому что каждый раз, когда я вхожу, она переключается обратно на светлую.*
6182
6283 Ей отвечает [Jakke Flemming (Jagster)](https://meta.discourse.org/t/dark-light-mode-toggle/215585/116), администратор из сообщества: посмотрите в настройках профиля. Совет верный — и он же доказывает разрыв: кнопка и профиль не знают друг о друге, и человек должен выставить одно и то же в двух местах.
6384
6485 Год спустя, [11 декабря 2024](https://meta.discourse.org/t/dark-light-mode-toggle/215585/158), тот же Jagster на тот же вопрос от следующего человека:
6586
6687 > It is always good policy to respect user's choises
6788 >
6889 > *Уважать выбор пользователя — всегда правильная политика.*
6990
7091 За четыре года в теме — 143 сообщения. Половина из них про одно и то же.
7192¶ **7 февраля 2025 — Осама переносит настройку на сервер.**
7293
7394 [Osama Sayegh](https://github.com/OsamaSayegh), инженер Discourse, вливает [PR #31086](https://github.com/discourse/discourse/pull/31086) «FEATURE: Dark/light mode selector» — 30 файлов, +1065/−111:
7495
7596 > 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
7697 >
7798 > *Этот PR делает компонент переключателя частью ядра, с улучшениями и исправлениями. […] у переключателя появляется вариант «Авто» […] заставка уважает выбранный режим*
7899
79100 Главное изменение не в списке, а в устройстве: localStorage заменён на cookie `forced_color_mode`. Cookie читает сервер. Значит, страницу можно сразу нарисовать нужного цвета — и вспышка, о которой Крис писал два года назад, исчезает. В [тот же день](https://github.com/discourse/discourse-color-scheme-toggle/commit/3cc674ffb36cf46f23f2a3fd3ccf0bfdf04f08ab) компонент Джордана объявлен устаревшим:
80101
81102 > This theme component has been folded into Discourse core
82103 >
83104 > *Компонент влит в ядро Discourse*
84105
85106 Настройка переехала из браузера на границу с сервером. Но не в аккаунт.
86107¶ **31 июля 2025 — и наконец в аккаунт.**
87108
88109 Ещё через полгода Осама присылает [PR #33875](https://github.com/discourse/discourse/pull/33875) «FEATURE: Color mode preference»:
89110
90111 > 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
91112 >
92113 > *ещё это позволяет задать режим по умолчанию для пользователя — он применится при входе с нового устройства. Задать режим для отдельного устройства по-прежнему можно*
93114
94115 `user_options.interface_color_mode`. Вопрос Сары из одной строки закрыт: тёмная по умолчанию, на любом устройстве, при любом входе. Вопрос Криса — тоже: переключатель пишет и на клиент, и в профиль.
95116
96117 И развилка, которую здесь решили явно: **настройка аккаунта и настройка устройства — разные вещи.** Обе нужны. Аккаунт — умолчание; устройство — уточнение. Cookie сильнее таблицы, потому что человек мог намеренно сделать телефон тёмным, а компьютер светлым.
97118¶ **Хвост.**
98119
99120 Дальше идёт то, что бывает, когда настройка наконец живёт в правильном месте, — её начинают доделывать со всех сторон.
100121
101122 **12 августа 2025** — [Krzysztof Kotlarek](https://github.com/discourse/discourse/pull/34165) убирает отдельную галочку тёмного режима из профиля: два органа управления одним и тем же — лишний.
102123
103124 **10 октября 2025** — [Kris (awesomerobot)](https://github.com/discourse/discourse/pull/35324), семь строк:
104125
105126 > Currently this color mode switcher has no accessible label or title, this adds both!
106127 >
107128 > *Сейчас у переключателя нет ни доступной подписи, ни title — добавляю обе!*
108129
109130 **9 января 2026** — [Régis Hanol (ZogStriP)](https://github.com/discourse/discourse/pull/37032), сооснователь Discourse, находит, что серверные страницы — 404, сброс пароля, приглашения — всё ещё берут логотип по системной теме:
110131
111132 > the `<source>` media query was hardcoded to `(prefers-color-scheme: dark)`, ignoring the `forced_color_mode` cookie.
112133 >
113134 > *media-запрос в `<source>` был зашит как `(prefers-color-scheme: dark)` и не учитывал cookie `forced_color_mode`.*
114135
115136 Это не баг переключателя. Это старый ответ 2020 года — «слушать систему», — переживший в одном месте все четыре переезда.
116137¶ **Здесь нет виноватых, и это важнее всего.**
117138
118 Пенар в 2020-м дал верный ответ про хранение — для того, что тогда было: выбор схемы в профиле. Джордан в 2020-м не мог писать в аккаунт: компонент темы по устройству живёт в браузере, и localStorage был единственным честным местом. Крис в 2023-м увидел причину, но перенос компонента в ядро — это +1065 строк и 30 файлов, ради кнопки, которая «и так работает». Осама сделал это, когда сошлись «Авто», заставка, логотипы категорий — когда переезд стал оправдан не одной жалобой, а десятком.
139+ Пенар в 2020-м дал верный ответ про хранение — для того, что тогда было: выбор схемы в профиле. Джордан в 2020-м пробовал обе двери: localStorage, через три недели cookie. Разницы не вышло cookie сервер прочитать может, но читать её было некому: компонент темы не заставит ядро рисовать страницу иначе. Пенар в 2022-м вернул localStorage и в том же PR объявил сброс возможностью, а через двадцать пять дней сам записал, как это выглядит со стороны человека. Крис в 2023-м увидел причину, но перенос компонента в ядро — это +1065 строк и 30 файлов, ради кнопки, которая «и так работает». Осама сделал это, когда сошлись «Авто», заставка, логотипы категорий — когда переезд стал оправдан не одной жалобой, а десятком.
119140
120141 А 143 сообщения в теме — это люди, которые по одному обнаруживали, что их выбор не запомнили, и каждому по одному объясняли, где лежит вторая настройка.
121142## Что это значит для нас
1221431. Хранить настройку человека у человека
123144 Выписать всё, что интерфейс запоминает про пользователя (тема, шрифт, язык, свёрнутые панели), и по каждому ответить: это про человека или про устройство? Первое — в аккаунт, второе — в cookie или localStorage.
124145 why: У нас оформление лежало в четырёх ключах localStorage. На айфоне у одного сайта три хранилища — Safari, ярлык на экране и встроенный браузер Telegram. Человек ставит тёмную в одном, приходит из другого — «сбросилась». Ровно жалоба Сары из 2023-го.
125146 - [ ] Настройки человека читаются из аккаунта на любом устройстве
126147 - [ ] Настройки устройства (свёрнутая панель) не тянутся в аккаунт
127148 → discourse#33875 — Color mode preference — https://github.com/discourse/discourse/pull/33875
1281492. Сделать cookie копией для сервера, а не хранилищем
129150 Если страницу рисует сервер, ему нужно знать тему до первого байта. Cookie для этого; пишет её только сервер, читается она, когда аккаунта нет.
130151 why: Вспышка противоположной темы при перезагрузке — то, о чём Крис писал в 2023-м. Она лечится не скриптом, а тем, что сервер знает ответ заранее. Discourse пришёл к cookie `forced_color_mode` в #31086.
131152 - [ ] `<html>` с сервера приходит уже нужного цвета, без перекраски скриптом
132153 - [ ] Инлайн-скрипт остался только для режима «как в системе»
133154 → discourse#31086 — Dark/light mode selector — https://github.com/discourse/discourse/pull/31086
1341553. Решить явно: аккаунт против устройства [recommended]
135156 Записать в одном месте, кто сильнее, когда аккаунт и устройство спорят. У Discourse сильнее устройство; у нас — аккаунт, и это осознанный выбор для портала, где у каждого один телефон и один компьютер.
136157 why: Два хозяина у одной настройки без явного приоритета — это трещина, которую Пенар описал в 2022-м: «если пользователь меняет оформление ОС, настройка сбрасывается».
137158 - [ ] Приоритет записан в коде одной строкой и в комментарии — почему так
138159 - [ ] Изменить его — правка одной строки, а не переезд хранилища
139160 → Пенар, 27.12.2022 — https://meta.discourse.org/t/dark-light-mode-toggle/215585/62
1401614. Перенести старые ключи, а не бросить
141162 При первом заходе после выката прочитать прежние ключи localStorage, записать в аккаунт, удалить. Компонент переноса убрать через пару месяцев.
142163 why: Иначе выкат сам станет «всё сбросилось» во второй раз. Правка ZogStriP’а в 2026-м — напоминание, что прежний ответ доживает в углах и после четырёх переездов.
143164 - [ ] У человека с выставленной раньше темой после выката она та же
144165 - [ ] Старых ключей в localStorage не остаётся
145166 → discourse#37032 — logo on server-rendered pages — https://github.com/discourse/discourse/pull/37032
1461675. Подписать кнопки, у которых только иконка [recommended]
147168 Пройти по проекту: элементы без текста внутри — с `aria-label` и `title`. Дешевле всего сделать подпись обязательной по типу в общем компоненте.
148169 why: Семь строк Криса в 2025-м. У нас такая же стрелка на карточках сводки была без имени.
149170 - [ ] Кнопка-иконка без подписи не проходит проверку типов
150171 - [ ] Читалка экрана объявляет назначение, а не «кнопка»
151172 → discourse#35324 — A11Y: aria-label, title — https://github.com/discourse/discourse/pull/35324
152173¶ Кнопка переключения темы — самая простая вещь в интерфейсе. Нажал — стало тёмным.
153174
154175 Пять лет ушло не на кнопку. На то, чтобы договориться, кому принадлежит ответ на неё: браузеру, системе, устройству или человеку.