Інтерфейсна система
Форма, ритм, стани й компоненти для всіх елементів інтерфейсу. Кожен блок — це правило і поруч живий приклад, з якого можна копіювати. Палітра й ролі кольору — у розділі Колір брендбуку.
Форма
Один жест на всю систему: три кути скруглені на 5 px, нижній лівий замінений на гостру діагональ 45°. Розмір зрізу береться зі сходинки, а не рахується з висоти елемента.
Сходинка зрізу
Зріз залежить від розміру елемента, але не пропорційно: чекбокс віддає під нього 23 % висоти, панель — 7 %. П'ять значень покривають усе, проміжних не буває.
до 24 px
чекбокс, тег
26–36 px
чип, малий btn
38–56 px
кнопка, поле
57–140 px
тулбар, меню
понад 140 px
панель, картка
Базові значення 5 / 8 / 12 / 18 / 26 множаться на --k: 0.7.
Крок xs має підлогу 5 px: нижче цього зріз перестає читатися на звичайному екрані.
Тонкі елементи
Смуга заввишки 6–18 px зрізу не витримує — він з'їв би всю висоту.
Такі елементи нахиляють ліву грань цілком на 10°, радіус падає до 2 px.
Дрібні квадратні плашки — бігунок, ручка слайдера — лишаються зі зрізом
xs: у них висота і ширина одного порядку.
Правила
Так
- Один зріз на групу: у сегментах і табах ріже тільки перший елемент
- У вертикальному списку зріз бере контейнер, рядки лишаються квадратними
- Найдрібніша плашка теж має зріз: бігунок 14 px бере крок
xs - Радіус завжди менший за зріз, інакше кут «з'їдає» діагональ
- У RTL жест дзеркалиться: зріз і акцентна смуга йдуть до початкової грані
Ні
- Зріз на кожному рядку списку — нижня кромка стає пилкою
border,outlineіbox-shadowна елементі зі зрізом: кліп їх ріже- Проміжні розміри зрізу «на око» замість сходинки
- Компенсація padding під зріз: вміст стоїть по центру, кут вільний
- Зріз в іншому куті або під іншим кутом на одному екрані
Пилка проти контейнера
Ритм і розмір
Відступи — крок 4 px, вісім значень. Висоти контролів — чотири, і кожна прив'язана до свого кроку зрізу. Проміжних значень у системі немає.
Відступи
Висоти контролів
Типографіка інтерфейсу
Сім кроків кегля, три інтерліньяжі. Все, що в інтерфейсі, живе тільки в цих значеннях — на відміну від текстових сторінок, де шкала ширша.
Так
- Інтерліньяж 1.2 для заголовків, 1.4 для UI, 1.6 для абзаців
- Uppercase — тільки мono 11 px з letter-spacing +10 %
- Мінімальний кегль у продукті — 11 px, і лише для мета-даних
- Вага 400 і 500 для тексту, 600 для заголовків
Ні
- Проміжні кеглі на кшталт 11.5 або 13.5 px
- Капс на Inter довшими за два слова
- Більше двох ваг у межах одного блока
- Cormorant SC в інтерфейсі: він для обкладинок, не для UI
Стани
Шість станів на кожен інтерактивний елемент. Стан ніколи не передається лише кольором — завжди є друга ознака: яскравість, маркер або позиція.
Фокус
outline і box-shadow зрізаються кліпом, тому фокус для елементів
зі зрізом — стек із чотирьох drop-shadow: він повторює силует. Спробуйте Tab.
filter створює containing block:
абсолютно спозиційовані нащадки всередині сфокусованого елемента почнуть рахувати
координати від нього, а position: fixed перестане бути fixed. Тому кільце
вішаємо на сам контрол, а не на контейнер із поповерами всередині.
Стан не тільки кольором
Так
Колір плюс іконка й підпис.
Ні
Тільки крапка: не читається при дальтонізмі.
Рівні й тіні
Три поверхні для площин і три тіні для того, що спливає над ними.
Тінь — це drop-shadow на батьківському елементі, бо box-shadow ріжеться кліпом.
Тінь по силуету
Зліва направо: --shadow-1 для наведеної картки, --shadow-2 для меню
й поповерів, --shadow-3 для модалок. Тінь висить на обгортці без кліпу —
drop-shadow обводить зрізаний силует, а не прямокутник.
clip-path контейнера зрізає
і абсолютно спозиційованих нащадків, тому меню, тултип і дропдаун у продакшені виносимо
в body. Усередині картки вони працюватимуть лише поки поміщаються в її межі.
Компоненти
Повний набір елементів у формі бренду — з них збираються екрани.
Кнопки
Групи
Поля
Вибір
Два маркери на всю систему: гостра галочка під 45° і ромб. Кіл немає ніде — радіо відрізняється від чекбокса маркером, а не формою рамки.
Чипи, теги, аватари
Прогрес і слайдер
Повідомлення
Акцент — смуга в самому фоні блока, чверть від зрізу. Низ у неї той самий 45°, що й кут.
Вузол eu-central-04 піднявся за 27 секунд.
Лишилося 8 % ліміту на поточний місяць.
Останній успішний запис — 14 хвилин тому.
Списки й меню
Рядок квадратний — у списку зріз належить контейнеру. Жест лишається на акценті: смуга завширшки з половину зрізу, а її низ зрізаний під ті самі 45°, тож вона закінчується вістрям.
Таблиця й пагінація
| Вузол | Регіон | Стан | Навантаження |
|---|---|---|---|
| eu-central-01 | Франкфурт | online | 62 % |
| eu-central-02 | Франкфурт | degraded | 91 % |
| us-east-01 | Ешберн | down | — |
Порожній стан і тултип
Кліп ріже пунктирну рамку, тому зону позначає штрихування під кутом зрізу.
стрілка не переживає кліп.
Рух
Три тривалості й одна крива. Рух пояснює зміну стану, а не прикрашає її.
Крива одна: cubic-bezier(.4, 0, .2, 1). Bounce і pulse у системі відсутні.
prefers-reduced-motion: reduce всі переходи
й анімації стискаються до 1 ms, спінер зупиняється на одному оберті. Стан має лишатися
зрозумілим і без руху — саме тому в кожного стану є друга ознака, крім анімації.
Токени
Повний набір змінних: спершу бренд — колір, градієнт і шрифти, далі все, з чого складається інтерфейс. Копіюється у проєкт як є.
:root {
/* Нейтралі */
--color-base: #0D1011;
--color-surface: #161A1D;
--color-surface-2: #22272B;
--color-border: #3B444B;
--color-pigeon: #8B959C;
--color-text: #F1F2F3;
/* Ядро бренду й акценти */
--brand-violet: #321467;
--brand-navy: #263ABA;
--brand-ocean: #4389E5;
--brand-azure: #A2C9F6;
--brand-flame: #FE9B22;
--brand-coral: #F86570;
--gradient-brand: linear-gradient(120deg, #321467 0%, #263ABA 42%, #4389E5 100%);
/* Другим у стеку йде затверджений fallback */
--font-display: "Cormorant SC", Georgia, "Times New Roman", serif; /* H1, вага 500 */
--font-heading: "Montserrat", Arial, Helvetica, sans-serif; /* H2, H3, вага 600 */
--font-body: "Inter", Arial, Helvetica, sans-serif;
--font-mono: "JetBrains Mono", "Courier New", monospace;
/* Форма */
--ca: 45deg; /* кут зрізу */
--k: 0.7; /* масштаб сходинки */
--r: 5px; /* радіус трьох інших кутів */
--angle: 10deg; /* нахил тонких елементів */
--cut-xs: max(5px, calc(5px * var(--k)));
--cut-sm: calc(8px * var(--k));
--cut-md: calc(12px * var(--k));
--cut-lg: calc(18px * var(--k));
--cut-xl: calc(26px * var(--k));
--shape-min: 12px; /* нижче живуть тільки маркери */
/* Ритм */
--sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px;
--sp-5: 24px; --sp-6: 32px; --sp-7: 48px; --sp-8: 64px;
/* Висоти контролів */
--h-xs: 28px; /* зріз sm */
--h-sm: 36px; /* зріз sm */
--h-md: 44px; /* зріз md — базова */
--h-lg: 52px; /* зріз md */
/* Типографіка */
--fs-100: 11px; --fs-200: 12px; --fs-300: 13px; --fs-400: 15px;
--fs-500: 17px; --fs-600: 20px; --fs-700: 26px;
--lh-tight: 1.2; --lh-ui: 1.4; --lh-text: 1.6;
/* Структурний колір */
--color-separator: #3B444B; /* декоративні лінії, 1.8:1 */
--color-line: #697680; /* межі контролів, 3.8:1 */
--color-placeholder: #7C868D; /* 5.1:1 на base */
/* Семантика */
--info: #4389E5; --info-fg: #A2C9F6; --info-bg: rgba(67,137,229,.14);
--success: #3FBF8F; --success-fg: #6FD9B0; --success-bg: rgba(63,191,143,.14);
--warning: #FE9B22; --warning-fg: #FFC178; --warning-bg: rgba(254,155,34,.14);
--danger: #F86570; --danger-fg: #FA8B93; --danger-bg: rgba(248,101,112,.14);
--on-solid: #0D1011; /* текст на суцільній заливці ролі */
--focus: #A2C9F6;
--disabled-opacity: .5;
/* Рівні: box-shadow ріжеться кліпом, тому тінь — filter на обгортці */
--shadow-1: drop-shadow(0 2px 6px rgba(0,0,0,.4));
--shadow-2: drop-shadow(0 10px 24px rgba(0,0,0,.5));
--shadow-3: drop-shadow(0 22px 50px rgba(0,0,0,.6));
/* Рух */
--dur-1: 120ms; --dur-2: 180ms; --dur-3: 260ms;
--ease: cubic-bezier(.4, 0, .2, 1);
}
.ch для плашок
(модифікатори --xs … --xl перемикають крок сходинки),
.sl для тонких смуг. Обидва — чистий CSS без JS: розмір зрізу абсолютний,
тому висоту міряти не треба.