Тема в Koobiq — это набор CSS-переменных. Смена темы меняет значения переменных, всё остальное остаётся как есть. Здесь описано, как подключить тему, как её переключать и как брать её значения в своих стилях.
Есть три уровня.
Глобальные переменные описывают дизайн-систему: цвета, размеры, шрифты. Они приходят из пакета @koobiq/design-tokens и объявлены под селектором темы — .kbq-light или .kbq-dark. Именно ими вы пользуетесь в своих стилях.
Переменные компонента нужны внутри компонентов Koobiq. Имя каждой начинается с названия компонента (--kbq-button-*, --kbq-alert-*), а значение ссылается на глобальную переменную. Компонент объявляет их сам, поэтому отдельно подключать ничего не нужно. Исключение — code-block, scrollbar и skeleton: их токены лежат в пакете @koobiq/design-tokens, но при обычном подключении и для них ничего делать не нужно — значения уже входят в файл готовых стилей.
Ваши стили обращаются к глобальным переменным напрямую. Ни импортов, ни миксинов, ни регистрации в едином источнике темы.
Подключить тему — значит поставить класс на <body>. Всё, что внутри, и компоненты, и ваша вёрстка, подхватит новые значения само, потому что читает одни и те же переменные.
css-tokens.css, css-tokens-light.css и css-tokens-dark.css — в них лежат глобальные значения.@use '@koobiq/components/prebuilt-themes/theme.css';<body>:<body class="kbq-app-background kbq-light">
<app></app>
</body>Класс kbq-app-background красит саму страницу — фон и цвет текста.
Для этого есть KbqThemeService. Он ставит нужный класс на <body>, запоминает выбор и в режиме 'auto' следует системной цветовой схеме.
Режима три: 'light', 'dark' и 'auto'. По умолчанию — 'auto'. Системная цветовая схема поддерживается из коробки: подписываться на matchMedia вручную не нужно.
Текущее состояние сервис отдаёт сигналами, их можно читать прямо в шаблоне:
protected readonly themeService = inject(KbqThemeService);<button kbq-button (click)="themeService.toggle()">
{{ themeService.colorScheme() === 'dark' ? 'Светлая тема' : 'Тёмная тема' }}
</button>Если тем больше двух и нужен список, а не переключатель «светлая/тёмная», тему можно закрепить по имени. Подробности и живой пример — на странице Core.
| Тема | Селектор |
|---|---|
| Светлая | .kbq-light |
| Тёмная | .kbq-dark |
Настройки передаются при запуске приложения:
import { kbqThemeProvider } from '@koobiq/components/core';
bootstrapApplication(AppComponent, {
providers: [kbqThemeProvider({ mode: 'auto', storageKey: 'my-app-theme' })]
});Выбор темы сохраняется между визитами — по умолчанию в localStorage, причём смена темы в одной вкладке подхватывается остальными открытыми вкладками приложения. Приложения, которые собираются на сервере, могут хранить его в куке: тогда сервер сразу знает, какую тему рисовать. Для этого подключите KbqThemeCookieStore через токен KBQ_THEME_STORE — он читает куку прямо из входящего запроса, больше на сервере ничего настраивать не нужно.
Напишите переменную там, где нужно значение:
.my-component-text {
color: var(--kbq-foreground-contrast-secondary);
}Ничего не импортируется, миксин писать не нужно, регистрировать его в едином источнике темы тоже. Значение подставляется в браузере, поэтому при смене темы оно меняется само.
Полный список глобальных переменных — на странице Дизайн-токены.
Если стандартный вид компонента не подходит, менять нужно не его стили, а значения его переменных. Сначала стоит понять, где эти переменные объявлены — от этого зависит, как до них дотянуться. Каждый компонент задаёт их на своём селекторе, в файле рядом с собой:
/* button-tokens.scss */
.kbq-button,
.kbq-button-icon {
--kbq-button-filled-contrast-fade-off-background: var(--kbq-background-contrast);
}Кнопка задаёт переменную на себе, поэтому общее объявление в :root она просто не увидит. Чтобы переопределение сработало, нужно попасть в тот же самый элемент.
Отсюда два рабочих способа.
Поменять один экземпляр. Повесьте на него свой класс и задайте переменную в нём — класс окажется на том же элементе, что и стандартное значение, и, поскольку идёт следом, победит:
<button kbq-button class="my-danger-button">Удалить</button>
<style>
.my-danger-button {
--kbq-button-filled-contrast-fade-off-background: var(--kbq-background-error);
}
</style>Поменять все компоненты этого типа в приложении. Здесь нужен селектор потяжелее, чем у самого компонента. Проще всего добавить перед ним селектор темы: заодно можно задать разные значения для светлой и тёмной, если один цвет на обе не годится:
.kbq-light .kbq-button {
--kbq-button-filled-contrast-fade-off-background: var(--kbq-background-error);
}
.kbq-dark .kbq-button {
--kbq-button-filled-contrast-fade-off-background: var(--kbq-background-error-fade);
}Такие правила удобно держать в одном файле и подключать его после стилей дизайн-системы — тогда все переопределения приложения лежат в одном месте, а не расползаются по компонентам.
Кастомный компонент читает те же глобальные переменные, что и библиотека. Дайте ему файл стилей и отключите изоляцию стилей — это вся настройка:
@Component({
selector: 'my-card',
templateUrl: './my-card.html',
styleUrl: './my-card.scss',
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class MyCard {}.my-card {
padding: var(--kbq-size-l);
border: var(--kbq-size-border-width) solid var(--kbq-line-contrast-less);
border-radius: var(--kbq-size-border-radius);
background: var(--kbq-background-card);
color: var(--kbq-foreground-contrast);
}Отдельный миксин _my-card-theme.scss, который потом нужно регистрировать в едином источнике темы, писать не надо.
Где браузер поддерживает corner-shape, компоненты скругляют углы сквирклом (corner-shape: squircle), в остальных браузерах — обычным радиусом. Сквиркл выглядит мельче дуги того же радиуса, поэтому радиус для него увеличивается. Чтобы углы вашего компонента совпадали с библиотечными, подключите миксин:
@use '@koobiq/components/core/styles/common/squircle' as *;
.my-card {
@include kbq-squircle(var(--kbq-size-border-radius));
}Без SCSS то же правило пишется вручную:
.my-card {
--my-card-radius: var(--kbq-size-border-radius);
border-radius: var(--my-card-radius);
}
@supports (corner-shape: squircle) {
.my-card {
corner-shape: squircle;
border-radius: clamp(
var(--my-card-radius) * 1.85,
var(--my-card-radius) * 2.3 - 3.6px,
var(--my-card-radius) * 2
);
}
}Радиус компонента библиотеки меняйте через его переменную (например, --kbq-button-size-border-radius), а не через border-radius. Увеличивается именно переменная: с голым border-radius угол останется сквирклом и будет выглядеть слишком мелким. Компоненту, скруглённому в круг через 50%, нужно ещё corner-shape: round.
Оформление всего приложения меняется в одном месте:
.kbq-light {
--kbq-background-contrast: #1a3a6b;
--kbq-foreground-contrast: #0d1b2a;
}
.kbq-dark {
--kbq-background-contrast: #7ba7e8;
--kbq-foreground-contrast: #e8eef7;
}Подключите этот файл после файлов дизайн-системы — и все компоненты подхватят новые значения.
Одна честная оговорка: так работает глобальный уровень. Переменные компонента объявлены на его селекторе, поэтому одним общим файлом до них не дотянуться — придётся писать правило на каждый компонент, как показано выше.
Глобальные переменные, со значениями и образцами: Дизайн-токены.
Переменные компонента объявлены рядом с его кодом, в файле токенов, например button-tokens.scss у кнопки: откройте его по ссылке Исходный код на странице компонента. В браузере инструменты разработчика показывают их на элементе компонента как CSS-переменные вида --kbq-button-*.
Токены дизайн-системы — это значения, которые задают внешний вид наших компонентов. Они лежат в пакете @koobiq/design-tokens.
Переменные компонентов — это значения, которые используются в стилях компонентов. Они получены из токенов дизайн-системы и лежат в репозитории @koobiq/components, рядом с самими компонентами.
Версия 4.0.0 пакета @koobiq/design-tokens удалила токены компонентов — кроме code-block, scrollbar и skeleton. Их токены поставляются отдельными файлами (component-tokens.css и его светлая и тёмная части), и их значения уже входят в prebuilt-themes/theme.css пакета @koobiq/components, так что подключать их самостоятельно не нужно. Остальные значения компоненты везут сами. Если копии удалённых токенов остались в ваших css-tokens.css, css-tokens-light.css, css-tokens-dark.css или css-tokens-font.css — удалите их, а затем запустите npx koobiq-tokens-codemod src, чтобы найти остальное, что затронуло обновление.