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

Раскладка

Рельс разделов

Вертикальная навигация одними значками, прижатая к краю окна. Разделы опознают по форме глифа, а не по слову, поэтому подписи в рельсе нет — она уходит в подсказку и в доступное имя.

Компонент
Разметка
<nav class="inst-rail" aria-label="Разделы">
  <a class="inst-rail-item" href="#рельс" aria-current="page" aria-label="Файлы">
    <svg class="inst-icon" aria-hidden="true"><use href="#i-list"/></svg>
  </a>
  <a class="inst-rail-item" href="#рельс" aria-label="Проекты">
    <svg class="inst-icon" aria-hidden="true"><use href="#i-grid"/></svg>
  </a>
  <a class="inst-rail-item" href="#рельс" aria-label="Прогоны">
    <svg class="inst-icon" aria-hidden="true"><use href="#i-refresh"/></svg>
    <span class="inst-badge inst-badge--count inst-rail-count">11</span>
  </a>
  <a class="inst-rail-item inst-rail-spacer" href="#рельс" aria-label="Параметры">
    <svg class="inst-icon" aria-hidden="true"><use href="#i-settings"/></svg>
  </a>
</nav>

Контракт

Рельс — это <nav> со своим именем и ряд ссылок внутри. Значок обязан нести aria-hidden, а имя раздела — жить в aria-label самой ссылки.

Что Обязательно Почему
aria-label на каждом пункте да Кнопка без текста не имеет доступного имени. Без него рельс читается как ряд пустых кнопок
aria-hidden на значке да Иначе скринридер зачитает содержимое SVG поверх имени
aria-current="page" на текущем да Заливка сообщает выбор глазу, атрибут — всему остальному
Подсказка при наведении нет, но желательно Форма глифа опознаётся не всеми и не сразу
Переход по адресу — <a> да Раздел имеет адрес, и средний клик обязан работать

Доступность

Доступное имя Только из aria-label. Значок — картинка, и текста в нём нет
Цель нажатия --control-h-lg, то есть 38px при обычной плотности и 32 при плотной — выше нормы 24 в обеих
Текущий раздел aria-current="page", а не только цвет: цвет как единственный носитель запрещён
Контраст глифа --text-secondary в покое, --accent-text у текущего — оба выше 4.5:1 в пяти темах
Ориентир <nav> с aria-label, иначе на странице два безымянных ориентира навигации

Устройство

Часть Что делает
.inst-rail Колонка. Ширина не задана числом: она складывается из отступа и кнопки, поэтому едет за плотностью
.inst-rail-item Кнопка --control-h-lg. Крупнее --tap-min намеренно: значок 24px в цели 24px заполнил бы её целиком
.inst-rail-spacer Прижимает остаток к низу. Учётная запись и параметры стоят внизу, а не отбиты отступом
.inst-rail-count Угол глифа снаружи. Изнутри счётчик закрыл бы форму, по которой раздел опознают

Текущий раздел несёт два носителя: заливку и метку у края. Одной заливки мало — на приглушённой поверхности рельса она едва отличается от наведения; метка видна периферийным зрением и не спорит с глифом.

API

Классы
ИмяЧто делает
класс
inst-railКолонка значков. Ширина интринсик: отступ плюс кнопка
inst-rail-itemРаздел. Ссылка или кнопка. aria-label обязателен
inst-rail-spacerРазрыв: всё после него прижимается к низу
inst-rail-countМесто под счётчик в углу глифа. Ставится на .inst-badge--count
Атрибуты
ИмяЗначениеЧто делает
атрибут
aria-currentpageТекущий раздел: заливка плюс метка у края
aria-label—Обязателен. Значок без имени не имеет доступного имени вовсе
Токены
ИмяЗначениеОткуда
переменная
--icon-sizeСтавится на пункт и наследуется значку. Через переменную, потому что раскладка лежит в более раннем слое, чем значок--size-icon-lgзадаёт приложение
токен
--size-icon-lgЗначок без подписи. Крупнее обычного намеренно24pxбаза +4: масштаб
--control-h-lgКнопка. Крупнее --tap-min, иначе глиф заполняет её целиком38pxбаза +14: плотность · масштаб
--size-markerМетка текущего у края2pxбаза +4: масштаб
--surface-sunkenlight-dark(var(--n-2), var(--n-14))база +1: тема
--surface-selectedcolor-mix(in oklab, var(--a-4) 14%, transparent)одно на все ячейки
--accent-marklight-dark(var(--a-4), var(--a-3))одно на все ячейки

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