CSS Custom Properties — полный список¶
Уровень: L3 (deep-dive) | Вверх: README.md | Раздел: ../README.md
Все дизайн-токены определены в двух файлах:
- frontend/src/theme/tokens.ts — сырые токены (JavaScript)
- frontend/src/theme/cssVars.css — CSS Custom Properties для использования в .module.css
Префикс всех CSS-переменных: --pl- (от «Плечики»).
Цвета¶
Основные¶
| Переменная | Значение | Назначение |
|---|---|---|
--pl-color-bg |
#F7F4EF |
Фон приложения (тёплый бежевый) |
--pl-color-surface |
#FFFDFB |
Фон карточек и поверхностей |
--pl-color-surface-alt |
#F2ECE3 |
Альтернативный фон (поля ввода) |
--pl-color-surface-overlay |
rgba(255, 253, 252, 0.85) |
Полупрозрачный фон с backdrop-blur |
--pl-color-surface-inverse |
#1F1B16 |
Инверсный фон (баннер, тост) |
Акцентные¶
| Переменная | Значение | Назначение |
|---|---|---|
--pl-color-accent |
#D18A62 |
Основной акцент (терракотовый) |
--pl-color-accent-soft |
rgba(209, 138, 98, 0.10) |
Мягкий акцент (фон выделенных элементов) |
--pl-color-accent-hover |
#C47D56 |
Hover-состояние акцента |
Текст¶
| Переменная | Значение | Назначение |
|---|---|---|
--pl-color-text |
#1F1B16 |
Основной текст |
--pl-color-text-secondary |
rgba(31, 27, 22, 0.72) |
Вторичный текст |
--pl-color-text-muted |
rgba(31, 27, 22, 0.55) |
Приглушённый текст (подписи, meta) |
--pl-color-text-inverse |
#FFFDFB |
Текст на тёмном фоне |
Границы¶
| Переменная | Значение | Назначение |
|---|---|---|
--pl-color-border |
rgba(31, 27, 22, 0.08) |
Границы карточек, разделители |
Состояния¶
| Переменная | Значение | Назначение |
|---|---|---|
--pl-color-success |
#5B8C51 |
Успешные операции |
--pl-color-warning |
#D4A12A |
Предупреждения |
--pl-color-danger |
#C4483F |
Ошибки, удаление |
--pl-color-danger-soft |
rgba(196, 72, 63, 0.10) |
Мягкий фон опасных действий |
Специальные¶
| Переменная | Значение | Назначение |
|---|---|---|
--pl-color-chip-dot |
#A7B29A |
Точка-индикатор (sage) |
--pl-color-chip-dot-soft |
#E4EADE |
Мягкая точка-индикатор |
Шрифты¶
| Переменная | Значение | Назначение |
|---|---|---|
--pl-font-display |
'Funnel Sans', sans-serif |
Заголовки (display, pageTitle, sectionTitle) |
--pl-font-body |
'Geist', sans-serif |
Основной текст, кнопки, подписи |
--pl-font-data |
'Geist Mono', monospace |
Данные, коды |
Размеры шрифтов¶
| Переменная | Значение | Элементы |
|---|---|---|
--pl-font-size-display |
28px |
AuthShell заголовки |
--pl-font-size-page-title |
24px |
PageHeader заголовки |
--pl-font-size-section-title |
20px |
Секции на страницах |
--pl-font-size-body |
15px |
Основной текст, описания |
--pl-font-size-caption |
13px |
FilterChip, подписи, OfflineBanner |
--pl-font-size-meta |
11px |
MediaCard meta, теги |
Отступы (spacing)¶
Шкала кратна 4px с шагом через 8px:
| Переменная | Значение | Использование |
|---|---|---|
--pl-space-2 |
8px |
Минимальный внутренний отступ |
--pl-space-3 |
12px |
Зазоры в сетках, gap между элементами |
--pl-space-4 |
16px |
Стандартный отступ (page padding) |
--pl-space-5 |
20px |
Увеличенный отступ между секциями |
--pl-space-6 |
24px |
Большой отступ (AuthShell padding) |
--pl-space-8 |
32px |
Максимальный отступ |
Скругления (border-radius)¶
| Переменная | Значение | Элементы |
|---|---|---|
--pl-radius-sm |
16px |
Изображения в карточках, thumbnail |
--pl-radius-md |
18px |
Ant Design message, inputs |
--pl-radius-card |
22px |
Карточки (SharedAccessRow) |
--pl-radius-sheet |
28px |
BottomSheet, AuthShell card |
--pl-radius-pill |
999px |
Кнопки, чипы, навигация |
Высоты контролов¶
| Переменная | Значение | Элементы |
|---|---|---|
--pl-control-height-sm |
38px |
FilterChip |
--pl-control-height-md |
52px |
Кнопки (PrimaryButton и др.) |
--pl-control-height-input |
54px |
Поля ввода |
--pl-control-height-nav |
74px |
Нижняя навигация (высота зоны) |
--pl-control-height-status-bar |
62px |
Status bar offset |
--pl-control-height-icon |
52px |
Круглые icon buttons |
--pl-control-height-header-btn |
40px |
Кнопка «назад» в PageHeader |
Layout¶
| Переменная | Значение | Назначение |
|---|---|---|
--pl-page-width |
390px |
Базовая ширина (iPhone 14) |
--pl-content-max-width |
768px |
Максимальная ширина контента |
--pl-page-padding |
16px |
Горизонтальный padding страниц |
--pl-screen-top-offset |
env(safe-area-inset-top, 0px) |
Отступ от верха (notch) |
--pl-screen-bottom-offset |
calc(var(--pl-control-height-nav) + env(safe-area-inset-bottom, 0px)) |
Отступ снизу (nav + safe area) |
Тени¶
| Переменная | Значение | Элементы |
|---|---|---|
--pl-shadow-soft |
0 1px 3px rgba(0,0,0,0.04) |
Мягкая тень (back button) |
--pl-shadow-card |
0 2px 8px rgba(0,0,0,0.04) |
Тень карточек |
--pl-shadow-floating |
0 4px 16px rgba(0,0,0,0.08) |
Floating элементы (ActionIconButton) |
--pl-shadow-sheet |
0 -4px 24px rgba(0,0,0,0.12) |
BottomSheet (тень вверх) |
Z-index¶
| Переменная | Значение | Элемент |
|---|---|---|
--pl-z-nav |
100 |
BottomNav |
--pl-z-sheet |
120 |
BottomSheet (Drawer) |
--pl-z-modal |
130 |
Modal, Confirm |
--pl-z-toast |
140 |
UpdateAvailableToast, messages |
Полный исходный код cssVars.css¶
:root {
/* ── colours ── */
--pl-color-bg: #F7F4EF;
--pl-color-surface: #FFFDFB;
--pl-color-surface-alt: #F2ECE3;
--pl-color-surface-overlay: rgba(255, 253, 252, 0.85);
--pl-color-surface-inverse: #1F1B16;
--pl-color-accent: #D18A62;
--pl-color-accent-soft: rgba(209, 138, 98, 0.10);
--pl-color-accent-hover: #C47D56;
--pl-color-text: #1F1B16;
--pl-color-text-secondary: rgba(31, 27, 22, 0.72);
--pl-color-text-muted: rgba(31, 27, 22, 0.55);
--pl-color-text-inverse: #FFFDFB;
--pl-color-border: rgba(31, 27, 22, 0.08);
--pl-color-success: #5B8C51;
--pl-color-warning: #D4A12A;
--pl-color-danger: #C4483F;
--pl-color-danger-soft: rgba(196, 72, 63, 0.10);
--pl-color-chip-dot: #A7B29A;
--pl-color-chip-dot-soft: #E4EADE;
/* ── fonts ── */
--pl-font-display: 'Funnel Sans', sans-serif;
--pl-font-body: 'Geist', sans-serif;
--pl-font-data: 'Geist Mono', monospace;
--pl-font-size-display: 28px;
--pl-font-size-page-title: 24px;
--pl-font-size-section-title: 20px;
--pl-font-size-body: 15px;
--pl-font-size-caption: 13px;
--pl-font-size-meta: 11px;
/* ── spacing ── */
--pl-space-2: 8px;
--pl-space-3: 12px;
--pl-space-4: 16px;
--pl-space-5: 20px;
--pl-space-6: 24px;
--pl-space-8: 32px;
/* ── radius ── */
--pl-radius-sm: 16px;
--pl-radius-md: 18px;
--pl-radius-card: 22px;
--pl-radius-sheet: 28px;
--pl-radius-pill: 999px;
/* ── control heights ── */
--pl-control-height-sm: 38px;
--pl-control-height-md: 52px;
--pl-control-height-input: 54px;
--pl-control-height-nav: 74px;
--pl-control-height-status-bar: 62px;
--pl-control-height-icon: 52px;
--pl-control-height-header-btn: 40px;
/* ── layout ── */
--pl-page-width: 390px;
--pl-content-max-width: 768px;
--pl-page-padding: 16px;
--pl-screen-top-offset: env(safe-area-inset-top, 0px);
--pl-screen-bottom-offset: calc(var(--pl-control-height-nav) + env(safe-area-inset-bottom, 0px));
/* ── shadows ── */
--pl-shadow-soft: 0 1px 3px rgba(0, 0, 0, 0.04);
--pl-shadow-card: 0 2px 8px rgba(0, 0, 0, 0.04);
--pl-shadow-floating: 0 4px 16px rgba(0, 0, 0, 0.08);
--pl-shadow-sheet: 0 -4px 24px rgba(0, 0, 0, 0.12);
/* ── z-index ── */
--pl-z-nav: 100;
--pl-z-sheet: 120;
--pl-z-modal: 130;
--pl-z-toast: 140;
}
html {
background: var(--pl-color-bg);
}
body {
font-family: var(--pl-font-body);
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-rendering: optimizeLegibility;
}
Полный исходный код tokens.ts¶
export const tokens = {
color: {
accent: '#D18A62',
accentSoft: 'rgba(209, 138, 98, 0.10)',
accentHover: '#C47D56',
bg: '#F7F4EF',
surface: '#FFFDFB',
surfaceAlt: '#F2ECE3',
surfaceOverlay: 'rgba(255, 253, 252, 0.85)',
surfaceInverse: '#1F1B16',
border: 'rgba(31, 27, 22, 0.08)',
text: '#1F1B16',
textSecondary: 'rgba(31, 27, 22, 0.72)',
textMuted: 'rgba(31, 27, 22, 0.55)',
textInverse: '#FFFDFB',
success: '#5B8C51',
warning: '#D4A12A',
danger: '#C4483F',
dangerSoft: 'rgba(196, 72, 63, 0.10)',
},
font: {
display: "'Funnel Sans', sans-serif",
body: "'Geist', sans-serif",
data: "'Geist Mono', monospace",
},
fontSize: {
display: '28px',
pageTitle: '24px',
sectionTitle: '20px',
body: '15px',
caption: '13px',
meta: '11px',
},
fontWeight: {
regular: 400,
medium: 500,
semibold: 600,
bold: 700,
},
lineHeight: {
display: 1.1,
title: 1.15,
body: 1.4,
caption: 1.25,
},
space: {
2: '8px',
3: '12px',
4: '16px',
5: '20px',
6: '24px',
8: '32px',
},
radius: {
sm: '16px',
md: '18px',
card: '22px',
sheet: '28px',
pill: '999px',
},
control: {
sm: '38px',
md: '52px',
input: '54px',
nav: '74px',
statusBar: '62px',
icon: '52px',
headerButton: '40px',
},
layout: {
pageWidth: '390px',
contentMaxWidth: '768px',
pagePadding: '16px',
},
shadow: {
soft: '0 1px 3px rgba(0, 0, 0, 0.04)',
card: '0 2px 8px rgba(0, 0, 0, 0.04)',
floating: '0 4px 16px rgba(0, 0, 0, 0.08)',
sheet: '0 -4px 24px rgba(0, 0, 0, 0.12)',
},
z: {
nav: 100,
sheet: 120,
modal: 130,
toast: 140,
},
};