Система иконок и пиктограмм
1) Роль иконок в продукте
Иконки — компактный носитель смысла и состояния. Они ускоряют сканирование, помогают экономить место и повышают узнаваемость паттернов. В продуктовых интерфейсах иконка дополняет текст и цвет, а не заменяет их.
Принципы:1. Смысл > стиль: каждая иконка должна иметь четкий сценарий применения.
2. Консистентность: единая сетка, штрих, углы, ритм заполнения.
3. Доступность: иконка не единственный сигнал; всегда есть подпись/tooltip/aria.
4. Производительность: один SVG-пайплайн, спрайты и токены цвета/размера.
2) Сетка и ключевые линии
Базовые артборды: 16×16, 20×20, 24×24 (основной), 32×32.
Ключевая линия (keyline): круг/квадрат, вписанный с отступом 1–2 px для оптического баланса.
Шаг пикселя: рисуем на целых координатах; stroke кратен 0.5 px (обычно 1.5 px на 24×24).
- Диагонали «толще» выглядят тоньше — добавьте 0.25 px к stroke в проблемных местах.
- Вершины острых углов чуть утапливаем внутрь keyline на 1 px, чтобы не «гремели».
- Кружки и точки часто требуют +1 px к диаметру для равной визуальной массы.
Зоны клика: интерактивная зона ≥ 40×40 px (mobile), ≥ 32×32 px (desktop); иконка центрирована.
3) Стиль набора
Линейный (outline) по умолчанию:- stroke: 1.5 px (24×24), 1.25 px (20×20), 1 px (16×16).
- linecap/linejoin: `round` для дружелюбности или `miter` для технического стиля (фиксируем в гайдлайне).
- Углы радиуса в геометрии: 2–3 px (на 24×24).
Заливка (filled) — для плотных областей и значков статуса.
Двухтон (duotone) — допускается для иллюстративных пустых состояний, но не для критичных UI-сигналов.
- Outline — базовое состояние.
- Filled — актив/выделение.
- Two-tone — декоративно/в справке.
4) Цвет и контраст (WCAG)
Базовый режим — монохром через `currentColor`: иконка наследует цвет текста/контекста.
Критичные статусы (ошибка/успех/предупреждение) — семантические токены:- `icon.error` ↔ фон ≥ 3:1, с подписью текстом (не только цвет).
- `icon.on-surface` ↔ фон ≥ 3:1; для мелких размеров целиться в 4.5:1.
- На цветных плашках используйте `on-` цвета (автоподбор контраста из системы цвета).
5) Состояния и взаимодействия
Default / Hover / Active / Disabled / Focus: разница не только в цвете — меняем непрозрачность/заливку/толщину/фон-пилюлю, добавляем focus ring.
Badges (счетчики): контраст цифры ≥ 4.5:1 к плашке; размер цифры ≥ 10–11 px.
Toggle-иконки (избранное, лайк): меняем заливку и/или внутреннюю точку, а не только цвет.
6) Иконка + текст
Иконки не заменяют лейблы в ключевых действиях. Минимальная пара: иконка + короткий текст (или tooltip по `aria-label`). В списках и таблицах иконка выравнивается по капвысоте текста и базовой линии.
7) Доступность (A11y)
Для декоративных иконок: `role="img" aria-hidden="true"` или убрать из потока доступности.
Для смысловых: `<svg role="img" aria-labelledby="id">` + `<title id="id">Описание</title>` или `aria-label`.
Иконка не должна быть единственным носителем статуса: добавляйте текст/подсказку/иконографический паттерн (форма, штрих).
Размер текста и контраст подписи соответствуют WCAG (обычный ≥ 4.5:1).
8) SVG-пайплайн и производительность
Почему SVG: векторная четкость, стилизация через CSS, малый вес с оптимизацией.
Рекомендации:- Хранить мастер-файлы в Figma, экспорт в SVG с опциями: без лишних `group`, без `fill-rule` по умолчанию, с атрибутом `viewBox` и без фиксированных `width/height` (переопределяем в CSS).
- Прогон через SVGO (профиль проекта): удаление метаданных, сокращение координат, объединение путей.
- Отказ от иконочных шрифтов (icon fonts) — проблемы с доступностью и рендером.
1. SVG-спрайт:
html
<svg style="display:none">
<symbol id="icon-upload" viewBox="0 0 24 24">…</symbol>
</svg>
…
<svg class="i"><use href="#icon-upload"></use></svg>
дешевые повторы, − нельзя легко менять `stroke-width` в некоторых пайплайнах.
2. Инлайн-SVG (React компонент): гибкость стилей и пропсов, tree-shaking.
3. External `<img>` — только для декоративных/иллюстративных.
css
.i { width: 1em; height: 1em; color: var(--icon-color, currentColor); }
.i--muted { opacity:.64; }
.i--danger { color: var(--role-danger); }
9) API компонента (пример React)
tsx type IconProps = {
name: 'upload' 'download' 'wallet' 'trophy' 'shield' string;
size?: number '1em' 'sm' 'md' 'lg';
stroke?: number; // 1 1. 25 1. 5 title?: string; // для a11y decorative?: boolean; // если true -> aria-hidden className?: string;
};
Поведение:
- По умолчанию `size="1em"` и `stroke=1.5`.
- Если `decorative` — добавляем `aria-hidden="true"`.