Перейти к содержимому
EN
Масштаб
Плотность
Тема
Акцент

Основания

Ритм и форма

Шаг 4px, шкала нарочно разрежена сверху — чтобы «чуть побольше» просто не было в наборе. Компонент берёт отступ не из шкалы, а из яруса ролей: именно он даёт плотности одну точку, через которую она перенастраивает всё сразу.

Компонент
worldgen-01
Генерация биомов, 3 прохода
готово
Разметка
<div class="inst-card inst-stack inst-stack--tight">
  <div class="inst-card-title">worldgen-01</div>
  <div class="inst-card-sub">Генерация биомов, 3 прохода</div>
  <div class="inst-cluster">
    <button class="inst-btn inst-btn--sm" type="button">Повторить</button>
    <span class="inst-badge" data-tone="ok"><span class="inst-dot"></span>готово</span>
  </div>
</div>

Контракт

Отступ берётся по назначению: --pad-panel, не --space-5. Роль перенастраивается плотностью, ступень шкалы — нет.

.my-panel {
  padding: var(--pad-panel);
  gap: var(--gap-row);
  border-radius: var(--radius-lg);
}
Что Обязательно Почему
Роль, а не ступень да --pad-panel меняется вместе с плотностью, --space-5 — нет. Компонент с зашитой ступенью ломается первым
Зазор ставит контейнер да Отступ у элемента складывается с внутренним отступом родителя по вертикали и не складывается по горизонтали
Радиус из словаря да Пять ступеней, названных размером контрола. Своё число разъезжается с соседями на стыке
Хайрлайн через --hairline да На дробном DPR это 0.5px, и линия остаётся линией, а не полосой

Доступность

Цели нажатия Отступ контрола участвует в размере цели наравне с высотой. В compact мелкие контролы уходят ниже 24px по WCAG 2.5.8 — см. плотность
Геометрия в px Отступы и радиусы не растут вместе с кеглем: плотный инструментальный вид иначе расползается. Растёт текст, а высоты работают как минимум
Разделение групп Ритм — тоже носитель смысла: четыре метрики без рамок читаются как одна группа именно зазором
Хайрлайн На 1x-дисплее остаётся 1px: линия, которая должна быть видна, видна на любом экране

Шкала

Компонент обращается к ней только через ярус ролей. Прямое использование --space-* допустимо в приложении и в примитивах потока.

Токен Значение
--space-1 2px
--space-2 4px
--space-3 6px
--space-4 8px
--space-5 12px
--space-6 16px
--space-7 24px
--space-8 32px
--space-9 48px
--space-10 64px

Разрежение сверху — не экономия, а ограничение: между 32 и 48 нет ступени, и это правильно. Шаг, которого нет, нельзя выбрать по ошибке.

Отступы по назначению

Ярус ролей. Значения ниже — для плотности по умолчанию; в compact и comfortable они другие, см. плотность.

Токен По умолчанию Где
--pad-panel --space-5 Внутренний отступ панели
--pad-card --space-6 Внутренний отступ карточки
--pad-cell-x --space-4 Горизонтальный отступ ячейки таблицы
--row-pad-y --space-3 Вертикальный отступ строки: задача, ячейка, пункт меню
--gap-row --space-3 Зазор между строками в стопке
--gap-inline --space-4 Зазор между соседями в ряду
--control-pad-sm --space-4 Горизонтальный отступ мелкого контрола
--control-pad-md --space-5 Он же у среднего
--control-pad-lg --space-6 Он же у крупного

Зазор ставится между соседями. margin-block на каждом элементе складывается с внутренним отступом контейнера сверху и снизу, но не по бокам — и подсветка отступает от рамки по вертикали вдвое дальше, чем по горизонтали. Правильная форма — X + X { margin-block-start }.

Размеры глифов и жёлобов

Тот же ярус ролей: у каждого размера есть имя, поэтому в компонентах нет констант.

Токен По умолчанию Что это
--size-dot 6px Точка состояния
--size-check 15px Чекбокс и радио
--size-switch-w / --size-switch-h 30 / 18px Дорожка свитча
--size-thumb 14px Бегунок
--size-track 4px Дорожка слайдера
--size-meter 6px Толщина меры
--size-spinner 14px Кольцо занятости
--size-icon 18px Иконка — см. иконки
--size-chevron 10px Шеврон, мелкая иконка
--size-marker 2px Несущая метка: полоса вкладки, край сноски, край текущего пункта навигации. Тоньше не видно, толще — спорит с текстом
--size-gutter 14px Левый жёлоб строки задачи
--size-indent 14px Шаг вложенности дерева
--label-col 104px Колонка подписей инспектора

Радиусы

Шесть ступеней, и выбирает их вложенность. Все значения чётные: при плотности 1.5 нечётный радиус растрируется мимо устройственной сетки.

Токен Значение Для чего
--radius-2xs 2px Нижняя ступень. Пометки достают её через --radius-mark, а не по имени
--radius-xs 4px Инлайн: бейджи, чипы, клавиша
--radius-sm 6px Контролы внутри карточки или панели
--radius-md 8px Отдельно стоящие контролы: кнопка, поле, поповер
--radius-lg 12px Карточки, панели, модалка
--radius-full 999px Дорожки, бегунки, аватар

Скругление КОНТРОЛА берётся не отсюда напрямую, а из --radius-control-sm/md/lg: оно едет за плотностью вместе с высотой, иначе мелкая кнопка читается пилюлей. См. плотность.

Скругление ПОМЕТКИ берётся из --radius-mark по причине обратного свойства. Мельче 8px лестница перестаёт предлагать выбор: когда два радиуса на одной стороне в сумме больше самой стороны, браузер молча ужимает все радиусы бокса, пока они не влезут. --radius-xs на точке 6px приезжает тройкой — это половина бокса, то есть круг; на метре 6px — той же тройкой, то есть пилюлей. А там, где вторая сторона бокса — это ДАННЫЕ (ширина отрезка дорожки, ширина штриха), форма начинает меняться вместе с данными. Ярус пометок — единственная ступень, которая переживает любую пометку в любом кегле.

Правило вложенных радиусов

Внутреннему углу нужен радиус меньше внешнего, иначе внутренний элемент выглядит выпирающим из контейнера. Оптически внутренний радиус равен внешнему минус толщина промежутка, и шкала уже подобрана так, чтобы соседняя ступень вниз давала верный результат при отступе из яруса ролей.

<!-- панель lg → контрол внутри sm; отдельно стоящий контрол — md -->
<div class="inst-panel">
  <div class="inst-panel-body">
    <div class="inst-card"></div>
  </div>
</div>

Скругление на односторонней рамке — всегда баг. border-left вместе с border-radius даёт обрубок дуги: сноска и край текущего пункта навигации несут прямой угол намеренно.

Хайрлайн

Браузер никогда не рисует рамку тоньше одного физического пикселя. На 1x-дисплее 0.5px и 1px дают одно и то же, а отрицательное поле в -0.5px при нарисованной рамке в 1px оставляет полпикселя двойной линии. Поэтому хайрлайн включается только там, где ему есть куда поместиться.

Токен Значение Когда
--hairline 1px Плотность пикселей ниже 1.5dppx
--hairline 0.5px @media (min-resolution: 1.5dppx)
--stroke 1px Линия, которая обязана остаться видимой всегда

Шов группы кнопок сделан снятой рамкой у соседа — по той же причине.

Правила

Токен Значение Что это
--aside-w 232px Боковая колонка оболочки
--container-max 76rem Потолок ширины рабочей области. В rem, потому что мера читаемости, а не геометрия
--split-side 18rem Желаемая ширина боковой части сплита
--split-main 30rem Ниже этого основная часть переносится вниз
--col-min 260px Минимальная колонка адаптивной сетки

Что брать, а что нет

Используйте Возьмите другое
Роль: --pad-panel, --gap-row, --row-pad-y --space-* в компоненте — плотность перенастраивает ярус ролей, а не шкалу. Список ролей целиком — токены
Зазор между соседями — примитив потока .inst-stack / .inst-cluster / .inst-grid Утилита отступа (mt-3, p-2) — их в библиотеке нет и не будет, см. поток
Шаг зазора именем: обычный, --tight, --loose Свой зазор числом — «чуть побольше» не должно быть доступным решением. Три шага описаны в потоке
Радиус по вложенности: контейнер lg, контрол внутри sm Один радиус на всё — внутренний элемент с радиусом контейнера выпирает. Пример — карточка
--hairline для линии, которая не должна кричать 1px числом — на 2x-дисплее это вдвое толще нужного, см. хайрлайн

API

Классы
ИмяЧто делает
класс
inst-stackВертикальный поток, зазор --gap-inline
inst-clusterГоризонтальный поток с переносом
inst-cluster-spacerРазрыв в ряду: всё после него уходит вправо
inst-gridАдаптивная сетка auto-fit по --col-min
модификатор
inst-stack--tightШаг зазора
inst-stack--looseШаг зазора
inst-cluster--tightШаг зазора
inst-cluster--looseШаг зазора
inst-grid--tightДругая минимальная колонка
inst-grid--wideДругая минимальная колонка
Токены
ИмяЗначениеОткуда
токен
--space-1Шаг шкалы2pxодно на все ячейки
--space-2Шаг шкалы4pxодно на все ячейки
--space-3Шаг шкалы6pxодно на все ячейки
--space-4Шаг шкалы8pxодно на все ячейки
--space-5Шаг шкалы12pxодно на все ячейки
--space-6Шаг шкалы16pxодно на все ячейки
--space-7Шаг шкалы24pxодно на все ячейки
--space-8Шаг шкалы32pxодно на все ячейки
--space-9Шаг шкалы48pxодно на все ячейки
--space-10Шаг шкалы64pxодно на все ячейки
--pad-panelВнутренний отступ панелиvar(--space-5)база +14: плотность · масштаб
--pad-cardВнутренний отступ карточкиvar(--space-6)база +14: плотность · масштаб
--pad-cell-xГоризонтальный отступ ячейкиvar(--space-4)база +14: плотность · масштаб
--row-pad-yВертикальный отступ строкиvar(--space-3)база +14: плотность · масштаб
--gap-rowЗазор между строкамиvar(--space-3)база +14: плотность · масштаб
--gap-inlineЗазор в рядуvar(--space-4)база +14: плотность · масштаб
--control-pad-smОтступ малого контролаcalc(var(--control-h-sm) * var(--control-ratio-sm))одно на все ячейки
--control-pad-mdОтступ базового контролаcalc(var(--control-h-md) * var(--control-ratio-md))одно на все ячейки
--control-pad-lgОтступ крупного контролаcalc(var(--control-h-lg) * var(--control-ratio-lg))одно на все ячейки
--radius-2xsНижняя ступень лестницы. Пометки берут её через --radius-mark2pxбаза +4: масштаб
--radius-markСкругление пометки: всё, что кит рисует мельче 8px — точка, штрих, метр и дорожкаvar(--radius-2xs)одно на все ячейки
--radius-xsИнлайн: бейджи, чипы, клавиша4pxбаза +4: масштаб
--radius-control-smСкругление мелкого контрола. Едет за плотностью вместе с высотойvar(--radius-sm)база +14: плотность · масштаб
--radius-control-mdСкругление контролаvar(--radius-md)база +14: плотность · масштаб
--radius-control-lgСкругление крупного контролаvar(--radius-md)база +14: плотность · масштаб
--radius-smКонтролы внутри карточки6pxбаза +4: масштаб
--radius-mdОтдельно стоящие контролы8pxбаза +4: масштаб
--radius-lgКарточки и панели12pxбаза +4: масштаб
--radius-fullКруг и капсула999pxодно на все ячейки
--hairlineВолосок. На 1x равен пикселю, выше — половине1pxбаза +1: экран
--strokeЛиния, которая обязана быть видна всегда1pxодно на все ячейки
--aside-wБоковая колонка оболочки232pxбаза +4: масштаб
--container-maxПотолок ширины рабочей области76remбаза +4: масштаб
--split-sideЖелаемая ширина боковой части сплита18remбаза +4: масштаб
--split-mainПорог переноса основной части30remбаза +4: масштаб
--col-minМинимальная колонка адаптивной сетки260pxбаза +4: масштаб
Классы
ИмяЧто делает
класс
inst-stackВертикальный поток, зазор --gap-inline
inst-clusterГоризонтальный поток с переносом
inst-cluster-spacerРазрыв в ряду: всё после него уходит вправо
inst-gridАдаптивная сетка auto-fit по --col-min
модификатор
inst-stack--tightШаг зазора
inst-stack--looseШаг зазора
inst-cluster--tightШаг зазора
inst-cluster--looseШаг зазора
inst-grid--tightДругая минимальная колонка
inst-grid--wideДругая минимальная колонка
Токены
ИмяЗначениеОткуда
токен
--space-1Шаг шкалы2pxодно на все ячейки
--space-2Шаг шкалы4pxодно на все ячейки
--space-3Шаг шкалы6pxодно на все ячейки
--space-4Шаг шкалы8pxодно на все ячейки
--space-5Шаг шкалы12pxодно на все ячейки
--space-6Шаг шкалы16pxодно на все ячейки
--space-7Шаг шкалы24pxодно на все ячейки
--space-8Шаг шкалы32pxодно на все ячейки
--space-9Шаг шкалы48pxодно на все ячейки
--space-10Шаг шкалы64pxодно на все ячейки
--pad-panelВнутренний отступ панелиvar(--space-5)база +14: плотность · масштаб
--pad-cardВнутренний отступ карточкиvar(--space-6)база +14: плотность · масштаб
--pad-cell-xГоризонтальный отступ ячейкиvar(--space-4)база +14: плотность · масштаб
--row-pad-yВертикальный отступ строкиvar(--space-3)база +14: плотность · масштаб
--gap-rowЗазор между строкамиvar(--space-3)база +14: плотность · масштаб
--gap-inlineЗазор в рядуvar(--space-4)база +14: плотность · масштаб
--control-pad-smОтступ малого контролаcalc(var(--control-h-sm) * var(--control-ratio-sm))одно на все ячейки
--control-pad-mdОтступ базового контролаcalc(var(--control-h-md) * var(--control-ratio-md))одно на все ячейки
--control-pad-lgОтступ крупного контролаcalc(var(--control-h-lg) * var(--control-ratio-lg))одно на все ячейки
--radius-2xsНижняя ступень лестницы. Пометки берут её через --radius-mark2pxбаза +4: масштаб
--radius-markСкругление пометки: всё, что кит рисует мельче 8px — точка, штрих, метр и дорожкаvar(--radius-2xs)одно на все ячейки
--radius-xsИнлайн: бейджи, чипы, клавиша4pxбаза +4: масштаб
--radius-control-smСкругление мелкого контрола. Едет за плотностью вместе с высотойvar(--radius-sm)база +14: плотность · масштаб
--radius-control-mdСкругление контролаvar(--radius-md)база +14: плотность · масштаб
--radius-control-lgСкругление крупного контролаvar(--radius-md)база +14: плотность · масштаб
--radius-smКонтролы внутри карточки6pxбаза +4: масштаб
--radius-mdОтдельно стоящие контролы8pxбаза +4: масштаб
--radius-lgКарточки и панели12pxбаза +4: масштаб
--radius-fullКруг и капсула999pxодно на все ячейки
--hairlineВолосок. На 1x равен пикселю, выше — половине1pxбаза +1: экран
--strokeЛиния, которая обязана быть видна всегда1pxодно на все ячейки
--aside-wБоковая колонка оболочки232pxбаза +4: масштаб
--container-maxПотолок ширины рабочей области76remбаза +4: масштаб
--split-sideЖелаемая ширина боковой части сплита18remбаза +4: масштаб
--split-mainПорог переноса основной части30remбаза +4: масштаб
--col-minМинимальная колонка адаптивной сетки260pxбаза +4: масштаб

Почему кит устроен именно так — конституция · Открытый код под MIT, github.com/keshon/instrument