Structuring, Grouping & Reusing
(Структура, группировка и переиспользование)
Чем больше становится ваш SVG-файл, тем сложнее в нем ориентироваться. Если вы рисуете сложную иллюстрацию или создаете систему иконок, просто накидывать <path> друг за другом — плохая идея.
В этом уроке мы разберем принцип DRY (Don't Repeat Yourself) в SVG: как группировать элементы, создавать шаблоны и переиспользовать их, не дублируя код.
1. Тег <g>: Группировка
Тег <g> (group) — это аналог <div> в HTML или «Папки» в графических редакторах. Он не отрисовывает ничего сам по себе, но объединяет вложенные элементы.
Зачем нужен:
- Организация кода: Логическое разделение (например,
<g id="head">,<g id="arm">). - Массовая трансформация: Можно сдвинуть, повернуть или уменьшить всю группу целиком.
- Наследование стилей: Атрибуты, заданные группе (например,
fillилиstroke), применяются ко всем вложенным элементам (если у них не заданы свои).
<svg width="200" height="200" viewBox="0 0 200 200">
<!-- Группа "Лицо": все элементы внутри будут красными и сдвинуты -->
<g id="face" fill="crimson" transform="translate(50, 50)">
<!-- Глаза (цвет наследуется от группы) -->
<circle cx="20" cy="20" r="10" />
<circle cx="80" cy="20" r="10" />
<!-- Рот (переопределяем цвет на белый) -->
<rect x="20" y="60" width="60" height="10" fill="white" />
</g>
</svg>
2. Тег <defs>: Склад ресурсов
<defs> (definitions) — это специальная область для хранения объектов. Всё, что находится внутри <defs>, не отображается на холсте автоматически. Это «склад» шаблонов, градиентов, фильтров или фигур, которые мы планируем использовать позже.
Это основа для оптимизации: вы определяете сложный объект один раз, а потом просто ссылаетесь на него.
<svg width="0" height="0">
<defs>
<!-- Этот круг не виден, пока мы его не позовем -->
<circle id="my-template" cx="10" cy="10" r="10" fill="teal" />
</defs>
</svg>
3. Тег <use>: Клонирование
Тег <use> достает объект из <defs> (или любого другого места по id) и отрисовывает его копию в нужном месте.
Преимущества:
- Уменьшение размера файла (код фигуры не дублируется).
- Единый источник правды (меняете фигуру в
<defs>— меняются все копии).
<svg width="300" height="100" viewBox="0 0 300 100">
<defs>
<circle id="coin" r="20" fill="gold" stroke="orange" stroke-width="2" />
</defs>
<!-- Используем монетку 3 раза в разных местах -->
<use href="#coin" x="50" y="50" />
<use href="#coin" x="150" y="50" />
<!-- Можно добавить трансформацию к копии -->
<use href="#coin" x="250" y="50" transform="scale(0.8)" />
</svg>
Примечание: В старых примерах кода вы можете встретить xlink:href. В современном SVG достаточно писать просто href.
4. Тег <symbol>: Золотой стандарт иконок
<symbol> — это продвинутая версия группы, созданная специально для переиспользования.
Главные отличия от <g> и <defs>:
- Как и
<defs>, содержимое<symbol>не отображается само по себе. - Киллер-фича: У
<symbol>есть свой собственный атрибутviewBox.
Это позволяет создавать SVG-спрайты (системы иконок). Неважно, как нарисована иконка внутри символа, вы можете вставить её через <use> и задать ей любые размеры (width и height), и она идеально впишется благодаря своему viewBox.
Пример SVG-спрайта
<svg style="display: none;">
<!-- Определение иконки "Дом" -->
<symbol id="icon-home" viewBox="0 0 24 24">
<path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"/>
</symbol>
<!-- Определение иконки "Настройки" -->
<symbol id="icon-settings" viewBox="0 0 24 24">
<path d="M19.14 12.94c.04-.3.06-.61.06-.94... (длинный путь) ..."/>
</symbol>
</svg>
Использование на странице
<!-- Большая иконка дома -->
<svg class="icon"><use href="#icon-home" width="50" height="50"/></svg>
<!-- Маленькая иконка настроек -->
<svg class="icon"><use href="#icon-settings" width="20" height="20"/></svg>
5. Shadow DOM и проблемы со стилизацией
Когда вы используете <use>, браузер создает Shadow DOM (Теневую модель документа). Это означает, что копия элемента изолирована от остальной страницы.
Проблема:
Вы не можете через CSS обратиться к внутренностям клона.
Например, такой CSS не сработает для изменения цвета пути внутри <use>:
/* Не сработает */
use path {
fill: blue;
}
Решение 1: Наследование (Inheritance)
Стили, заданные самому тегу <use>, наследуются внутрь Shadow DOM.
Чтобы это работало, внутри исходного символа не должно быть атрибута fill (или он должен быть currentColor).
Исходник:
<symbol id="star" viewBox="0 0 24 24">
<!-- Убираем fill="black", ставим fill="currentColor" или вообще удаляем -->
<path d="..." fill="currentColor" />
</symbol>
Использование:
<svg class="icon-red"><use href="#star" /></svg>
<svg class="icon-blue"><use href="#star" /></svg>
CSS:
.icon-red { color: red; } /* currentColor возьмет это значение */
.icon-blue { fill: blue; } /* Или так */
Решение 2: CSS Переменные
CSS переменные (Custom Properties) проникают сквозь границу Shadow DOM.
<symbol id="robot">
<rect fill="var(--main-color, black)" />
</symbol>
svg { --main-color: purple; }
Итог
<g>— для группировки частей одного рисунка (двигать вместе, красить вместе).<defs>— для хранения градиентов и масок.<symbol>+<use>— стандарт для иконочных систем. Позволяет управлятьviewBoxкаждой иконки отдельно.- Используйте
currentColorв путях иконок, чтобы легко перекрашивать их через CSS при использовании<use>.