Основания
Иконки
Inline SVG на сетке 16, обводка currentColor толщиной 1.5. Иконка наследует
цвет текста, поэтому в ките нет ни одного иконочного варианта тона.
Разметка
<button class="inst-btn" type="button">
<svg class="inst-icon" aria-hidden="true"><use href="#i-refresh"/></svg>
Обновить
</button>
<button class="inst-btn inst-btn--icon" type="button" aria-label="Настройки">
<svg class="inst-icon" aria-hidden="true"><use href="#i-settings"/></svg>
</button>
Использование
Пять требований. Нарушение любого видно сразу — иконка либо съезжает по базовой линии, либо перестаёт менять цвет вместе с текстом.
| Требование | Почему |
|---|---|
Inline SVG (или <use> из спрайта) |
Иконка обязана менять цвет вместе с текстом. <img> и background-image этого не умеют |
stroke: currentColor, fill: none |
Один файл работает во всех шести темах и во всех тонах без единого варианта |
| Толщина обводки 1.5 | Общая с хайрлайном оптика: 1 читается как царапина, 2 — как жирный шрифт рядом с 400 |
Сетка 16 (viewBox="0 0 16 16") |
Совпадает с --size-icon. Другая сетка даёт другую оптическую толщину при том же stroke-width |
| Цвет не живёт в data-URI | Форма рисуется маской, цвет приходит токеном. Иначе тема иконку не догоняет |
Класс .inst-icon объявляет это плюс flex: none — иначе иконка
сжимается первой, когда подпись рядом не помещается.
.inst-icon {
flex: none;
inline-size: var(--size-icon);
block-size: var(--size-icon);
fill: none;
stroke: currentColor;
stroke-width: 1.5;
stroke-linecap: round;
stroke-linejoin: round;
}
Разметка
| Случай | Разметка |
|---|---|
| Иконка рядом с подписью | aria-hidden="true" на <svg>. Имя даёт подпись; без атрибута скринридер прочитает элемент дважды или невнятно |
| Иконка вместо подписи | aria-hidden="true" на <svg> и aria-label на кнопке. Кнопка без текста иначе не имеет доступного имени |
| Иконка внутри ссылки | То же самое: имя несёт ссылка |
| Иконка как единственный носитель информации | Так не бывает. Добавьте подпись или aria-label — цвет и форма не имеют права быть единственным носителем |
Когда использовать
| Используйте | Возьмите другое |
|---|---|
| Иконка рядом с подписью — второй носитель смысла | Иконка вместо подписи в списке действий — в меню подпись обязательна, см. меню в поповере |
Иконка вместо подписи там, где действие общеизвестно и есть aria-label |
Иконка вместо статуса — статус несёт точку и слово, см. бейдж |
| Иконка как второй признак тона у сноски | Цвет как единственный носитель — закон кита. Тон описан в цвете |
<use href="#i-*"> из спрайта |
Текстовый глиф ⟳ или ▶ — разные метрики в разных шрифтах и риск подстановки эмодзи |
.inst-icon--sm в шевроне и мелком контроле |
Своя ширина инлайном — размер приходит из ролей: --size-icon и --size-chevron |
Устройство
Спрайт объявляется один раз на документ, до первого <use>. Сам он невидим и
скрыт от скринридера.
<svg class="inst-sprite" aria-hidden="true" focusable="false" xmlns="http://www.w3.org/2000/svg">
<symbol id="i-refresh" viewBox="0 0 16 16">…</symbol>
</svg>
Использование:
<svg class="inst-icon" aria-hidden="true"><use href="#i-refresh"/></svg>
У <svg> в месте использования нет собственного viewBox: он приходит из
<symbol>. Собственный viewBox на внешнем элементе перебивает символьный и
обрезает часть глифов.
Доступные id
Набор намеренно маленький: иконка заводится под задачу, а не «на всякий случай». Список печатается из самого спрайта — набранный руками он уже однажды разошёлся с китом на четыре символа.
i-booki-charti-checki-chevroni-closei-copyi-gridi-listi-logouti-morei-movei-refreshi-rotatei-scalei-settingsi-themei-usersПлюс 81 символов страниц справочника (i-p-*) — они принадлежат сайту, а не киту.
Размеры
| Класс | Размер | Токен | Где |
|---|---|---|---|
inst-icon |
16px | --size-icon |
Умолчание: кнопка, пункт меню, сноска, шапка |
inst-icon--sm |
10px | --size-chevron |
Шеврон селекта, метка внутри мелкого контрола |
Третьего размера нет. Иконка крупнее 16 в этом ките — это либо иллюстрация (её место в пустом состоянии), либо ошибка иерархии: иконка обслуживает данные и обязана быть тише их.
Размеры не реагируют на плотность намеренно — см. плотность: иконка носитель значения, и на 12px обводка 1.5 превращается в кляксу.
Композиции
<div class="inst-menu" role="menu">
<button class="inst-menu-item" type="button" role="menuitem">
<svg class="inst-icon" aria-hidden="true"><use href="#i-refresh"/></svg>Перезапустить
</button>
<button class="inst-menu-item" type="button" role="menuitem">
<svg class="inst-icon" aria-hidden="true"><use href="#i-copy"/></svg>Скопировать id
</button>
</div>
Иконочная кнопка квадратная: ширина берётся из той же высоты контрола, поэтому квадрат сохраняется во всех трёх размерах и во всех плотностях. Прямоугольник 32×28 — самый частый признак самодельного кита.
Доступность
| Декоративная иконка | aria-hidden="true" всегда, без исключений: имя даёт подпись или aria-label |
| Кнопка без текста | Обязана нести aria-label. Иначе у неё нет доступного имени вовсе |
| Контраст | Иконка наследует цвет текста, поэтому проходит те же пороги. Иконка на --text-faint — декорация и не имеет права нести смысл |
| Цвет не единственный носитель | Иконка сама по себе второй носитель тона (сноска), но не первый: тон обязан быть ещё и в тексте |
| Режим принудительных цветов | Обводка currentColor переживает сброс, потому что цвет берётся от текста, а не задан своим значением |
| Фокус | На <svg> фокуса не бывает: фокусируется кнопка или ссылка вокруг него, focusable="false" у спрайта убирает старый IE-артефакт |
Настройка
- Нарисуйте на сетке 16×16, только обводкой.
- Уберите
fill,stroke,stroke-widthиз самих путей — они придут из.inst-icon. - Скруглите концы и стыки не в файле, а классом:
stroke-linecapиstroke-linejoinуже там. - Положите в спрайт как
<symbol id="i-…" viewBox="0 0 16 16">. - Проверьте на тёмной теме: обводка на 1.5 в тёмной теме оптически тоньше, и слишком мелкая деталь исчезает.
API
| Имя | Значение | Что делает |
|---|---|---|
| класс | ||
inst-sprite | — | Спрайт в теле страницы. Прячет его: без правила это видимый блок в 150px |
inst-icon | — | Базовый. Обязателен всегда |
| модификатор | ||
inst-icon--sm | — | Уменьшение до --size-chevron |
| токен | ||
--size-icon | 16px | |
--size-chevron | 10px | |
--stroke | 1px | |
Почему кит устроен именно так — конституция · Открытый код под MIT, github.com/keshon/instrument