Двухуровневая палитра и темы
В styles/tokens.css собраны все цвета, которыми пользуются таблицы стилей и компоненты; единственное исключение — тоновая пара направления, которую реестр сайта поставляет как данные. Файл написан в два уровня — сырая палитра пигментов бумаги и туши и построенные на ней семантические токены, — а семантический уровень существует в двух контекстах, потому что страницы вики бывают двух родов: колонка, которую читают, и полка, с которой выбирают.
§1.1Уровень 1: пигменты
Сырая палитра — ящик красок художника, не зависящий от темы, с именами --p-*. Бумаги: фон навигации 纸 и лицо его карточек 页, фон чтения 素 (на ступень холоднее — глазам легче на длинной дистанции) и его мягкая поверхность 帛, белая карточка, подложки кода и формул. Туши: тёплый набор для полки и нейтральный для колонки, каждый в трёх насыщенностях. Переплёт: линейка полки, рамка пилюль, две волосяные линии. И пигменты — цвета, несущие смысл:
--p-zhu: #7d3a3a; /* 朱 · винный красный — акцент навигации, знак сайта */
--p-shi: #b6552e; /* 石 · жжёный оранжевый — акцент чтения: ссылки, номера, надзаголовки */
--p-shi-text: #8f3f1f; /* 石 · ступень для мелкого текста (AA на собственной подложке) */
--p-zhe: #c08a2c; /* 赭 · охра — линии и рамки */
--p-dai: #2a6f6b; /* 黛 · бирюза — второй акцент контента */
--p-zi: #6b4ec4; /* 紫 · фиолетовый — «системная» семантика */Плюс ночной набор для тёмного издания: сумеречные фоны, лунно-белые туши и высветленный двойник каждого пигмента.
§1.2Два контекста, одна палитра
Второй уровень — то, что потребляет слой компонентов, и у него два лица:
| Контекст | Токены | Фон | Тушь | Акцент | Где |
|---|---|---|---|---|---|
| колонка чтения | --color-* | 素 #fbf9f4 | нейтральная #1f2024 | 石 жжёный оранжевый | страницы заметок, все компоненты контента, base.css |
| полка навигации | --wb-* | 纸 #faf6ec | тёплая #2b2622 | 朱 винный красный | главная и страницы рубрик, вики-компоненты, browse.css |
Колонка — тише из двух: в ней проводят час. Полка теплее и набрана заголовочной антиквой: на неё бросают взгляд и выбирают. Страница входит в контекст полки одним классом wb-root на body; внутри него токены обвязки (--color-bg, --color-accent, …) переназначены на токены полки, поэтому написанная один раз панель навигации верно сидит на обоих фонах — а атомы таксономии (бейдж типа, точка статуса, чип направления), написанные против --color-*, на странице заметки читаются частью колонки, на обзорной — частью полки. Слою компонентов разрешён только второй уровень — это base.css, browse.css и каждый компонент; ни одно правило не содержит сырого цветового значения, и ничто не подставляет его как запасной вариант. Такова жёсткая дисциплина пакета.
§2.1Как сайт задаёт свою айдентику
Переопределяйте первый уровень. Замените пигменты своими — оба контекста и весь слой компонентов последуют сами. Каждый пигмент — дневная и ночная пара: светлая тема читает --p-shi и --p-zhu, тёмная — их ночных двойников --p-shi-n и --p-zhu-n; переопределение айдентики задаёт оба члена пары, либо тьма остаётся на пигментах по умолчанию:
:root {
--p-shi: #b03a48; /* ваш акцент чтения */
--p-shi-text: #93303c; /* его ступень для мелкого текста затемняется отдельно — см. ниже */
--p-zhu: #3b4a7a; /* ваш акцент полки и знак сайта */
--p-shi-n: #e0919b; /* ночные двойники, высветленные под сумеречные фоны */
--p-zhu-n: #9fb0e4;
}Столь же законный путь — переназначить второй уровень на собственную палитру, если она у вашей дизайн-системы уже есть: направьте --color-* и --wb-* на свои переменные. Этот сад намеренно не переопределяет ничего: перед вами голое лицо пакета — то самое, за которое агитирует «Бумага и тушь».
§2.2Контраст под аудитом
Каждое текстовое значение выверено на WCAG AA для каждой поверхности, на которой оно оказывается: мелкий текст начинается с 4.5:1; акцент, попадающий в мелкий текст, получает отдельно затемнённую текстовую ступень (--p-shi-text, --p-zhe-text), потому что подпись в 12px акцентного цвета обычно лежит на подложке того же акцента; блёклые туши взяты самыми тёмными из тех, что ещё читаются блёклыми — #6a6d74 на фоне чтения даёт 4.9:1 и всё ещё 4.5:1 на мягкой поверхности; подложка кода на ступень светлее бумаги, чтобы самый бледный токен синтаксической темы (комментарии) проходил 4.5:1; у тёмного издания собственный высветленный набор, промеренный на ночных фонах. Пакет поставляет измерение как инструмент: scripts/contrast_probe.mjs отрисовывает демо в настоящем браузере, в обеих темах и на двух ширинах, снимает фон под каждым текстовым фрагментом прямо с пикселей и докладывает о каждом, кто не добрал до планки (зонд контраста). Прежде чем менять любое значение — узнайте все поверхности, на которых оно лежит.
§2.3Светлая тема — и есть айдентика
Тема намеренно не читает prefers-color-scheme: страница не имеет права сменить тему под читателем. Тьма включается только через [data-theme='dark'] — переключателем самого сайта (кнопка солнца и луны справа в панели навигации; выбор хранится в localStorage под ключом inkstone-theme и воспроизводится инлайн-скриптом ThemeInit до первой отрисовки, так что читатель тёмной темы не видит кремовой вспышки). Тьма — не инверсия, а второе издание ручного набора: сумеречные фоны, лунно-белые туши, заново высветленные пигменты — «тьма — второе издание, а не инверсия».
§2.4Шрифты тоже живут здесь
Четыре стека. --font-display — лицо полки: антиква с оптическими размерами (Source Serif 4, для иероглифики Noto Serif SC) для шапок и заголовков полки; демо размещает её у себя через @fontsource, а сайт без неё откатывается на шрифт чтения. --font-body — шрифт колонки: системный стек антиквы во главе с Charter и Iowan Old Style; там, где их нет, подхватывает заголовочная гарнитура. --font-ui — Inter (Noto Sans SC для иероглифики): заголовки, обвязка и мелкий набор. --font-mono — сабсет Maple Mono CN с фиксированным набором знаков (ASCII + псевдографика + 3500 употребительных иероглифов + объединение всего уже написанного контента): латиница по 0.6em, иероглиф по 1.2em — иероглиф занимает ровно два знакоместа, поэтому диаграммы из псевдографики не расползаются даже в смешанном китайско-латинском тексте. Рецепт сабсета и скрипт регенерации едут с пакетом (fonts/build_font_subset.py); когда контенту нужны глифы за пределами покрытия, перезапустите его и закоммитьте woff2. Рамки для кода набраны сабсетом целиком.