SVG
SVG pipeline обеспечивает централизованное управление иконками: оптимизацию, генерацию React-компонентов, типизацию и единый интерфейс использования через компонент Icon.
Когда нужен SVG pipeline
MUST
Build pipeline необходим, если хотя бы одно условие верно:
- Дизайн предоставляет кастомные SVG
- Планируется ребрендинг или темизация
- Иконки используются в нескольких подпроектах
Pipeline: что должно получиться
Требования к исходникам
MUST
- Все SVG лежат в одной директории:
icons/
arrow-left.svg
check.svg
warning.svg
-
Имена файлов в kebab-case и совпадают с дизайном:
- ✅
arrow-left.svg,user-profile.svg - ❌
ArrowLeft.svg,arrow_left.svg
- ✅
-
Обязательно присутствует
viewBox:
<!-- ✅ Правильно -->
<svg viewBox="0 0 24 24">
<!-- ❌ Неправильно -->
<svg width="24" height="24">
- Монохромные иконки используют
currentColor:
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor">
<path d="..." />
</svg>
SHOULD
- Единый базовый размер (например, 24×24)
- Одинаковые правила для stroke/linecap/linejoin
FORBIDDEN
- Inline-стили внутри SVG:
<!-- ❌ Неправильно -->
<path style="fill: red; stroke: blue;" d="..." />
<!-- ✅ Правильно -->
<path fill="currentColor" d="..." />
- Жёстко заданные width/height без viewBox:
<!-- ❌ Неправильно -->
<svg width="24" height="24">
<!-- ✅ Правильно -->
<svg viewBox="0 0 24 24">
- Растровые вставки (
<image>внутри SVG)
Цвет и стилизация
MUST
- Монохромные иконки наследуют цвет через
currentColor:
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor">
<path d="..." />
</svg>
- Многоцветные иконки используют токены:
<svg viewBox="0 0 24 24">
<path fill="var(--color-icon-accent)" d="..." />
<path fill="var(--color-icon-secondary)" d="..." />
</svg>
Примеры
/* ✅ Правильно — currentColor */
<Icon name="arrow-left" className="text-primary" />
/* ✅ Правильно — токен */
<Icon name="warning" style={{ color: 'var(--color-warning)' }} />
/* ❌ Неправильно — захардкоженный цвет в SVG */
<svg><path fill="#ff0000" /></svg>
Использование в коде
MUST
Всегда использовать компонент Icon из UI-kit:
import { Icon } from '@/shared/ui/Icon';
<Icon name="arrow-left" size="m" />
<Icon name="warning" aria-label="Предупреждение" />
FORBIDDEN
Прямой импорт SVG:
/* ❌ Неправильно */
import ArrowLeft from './icons/arrow-left.svg';
<ArrowLeft width={16} height={16} />;
Анимации и inline-SVG
SHOULD
Для анимаций использовать CSS:
<Icon name="spinner" className="animate-spin" />
.animate-spin {
animation: spin 1s linear infinite;
}
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
MAY
Inline-SVG допускается для сложных анимаций:
- Анимации по путям (path animations)
- Морфинг форм
- Сложные keyframes, которые нельзя реализовать через CSS
/* ✅ Допустимо для сложной анимации */
<svg viewBox="0 0 100 100">
<path d="...">
<animate attributeName="d" dur="1s" ... />
</path>
</svg>
Доступность
MUST
- Декоративные иконки скрыты от скринридеров:
<Icon name="chevron-right" aria-hidden />
- Информативные иконки имеют доступное имя:
<Icon name="warning" aria-label="Предупреждение" />
<!-- или с визуальным текстом -->
<button>
<Icon name="save" aria-hidden />
<span>Сохранить</span>
</button>
Исключение: внешние библиотеки
Если дизайн-система полностью опирается на внешнюю библиотеку (Material Icons, Font Awesome), отдельный SVG pipeline может не требоваться.
MUST
Всё равно использовать единый компонент Icon как обёртку:
// ✅ Правильно — обёртка над Material Icons
import { Icon } from '@/shared/ui/Icon';
<Icon name="arrow-left" />;
// Внутри компонента Icon:
import { ArrowLeft } from '@mui/icons-material';
export const Icon = ({ name }) => {
const IconComponent = iconMap[name];
return <IconComponent />;
};