Практическое руководство: Анимация SVG с помощью <use> и CSS-переменных

Практическое руководство: Анимация SVG с помощью <use> и CSS-переменных

Элементы <symbol> и <use> в SVG позволяют создавать переиспользуемые графические элементы. Однако их анимация может быть сложной из-за ограничений Shadow DOM. В этом руководстве вы узнаете, как использовать CSS-переменные для анимации элементов внутри <symbol>.

Основная проблема: Barrier Shadow DOM

Когда вы ссылаетесь на содержимое <symbol> через <use>, браузер создает его копию в Shadow DOM. Это означает, что внешние CSS-стили не могут напрямую воздействовать на элементы внутри символа.

НЕ РАБОТАЕТ:

<symbol id="outlaw-1">
  <g class="outlaw-1-foot">...</g>
</symbol>

<use href="#outlaw-1" class="tapping" />
.tapping {
  animation: tapping 1s ease-in-out infinite; /* Не сработает! */
}

Решение: CSS-переменные

Обычные CSS-значения не могут преодолеть границу Shadow DOM, но CSS-переменные могут. Это ключ к анимации элементов внутри <symbol>.

Шаг 1: Подготовка символа

Добавьте CSS-переменные через inline-стили в элементы внутри символа:

<symbol id="outlaw-1">
  <g class="outlaw-1-foot" style="
    transform-origin: bottom right; 
    transform-box: fill-box; 
    transform: rotate(var(--foot-rotate, 0deg));">
    <!-- ... -->
  </g>
</symbol>

Несколько анимированных элементов внутри одного SVG-символа

Шаг 2: Создание анимации

Определите ключевые кадры, изменяющие CSS-переменные:

@keyframes tapping {
  0%, 60%, 100% { --foot-rotate: 0deg; }
  20% { --foot-rotate: -5deg; }
  40% { --foot-rotate: 2deg; }
}

Шаг 3: Применение анимации

Примените анимацию к элементам <use>:

use[data-outlaw="1"] {
  --foot-rotate: 0deg;
  animation: tapping 1s ease-in-out infinite;
}

Практические примеры

Пример 1: Многоцветная система иконок

Создайте переиспользуемые иконки с настраиваемыми цветами:

<symbol id="icon-bluesky">
  <path fill="var(--icon-fill, currentColor)" d="..." />
</symbol>

Использование с разными цветами:

<header>
  <svg xmlns="http://www.w3.org/2000/svg">
    <use href="#icon-bluesky" style="--icon-fill: #2d373b;" />
  </svg>
</header>

<footer>
  <svg xmlns="http://www.w3.org/2000/svg">
    <use href="#icon-bluesky" style="--icon-fill: #590d1a;" />
  </svg>
</footer>

Кастомные свойства для цветов заливки в нескольких иконках Bluesky

Пример 2: Визуализация данных

Создайте инфографику с переиспользуемыми элементами:

<symbol id="career-bar">
  <rect
    height="10"
    width="var(--career-length, 100)" 
    fill="var(--career-colour, #f7bea1)"
  />
</symbol>

Использование для разных наборов данных:

<use href="#career-bar" style="--career-length: 400; --career-color: #769099;"/>
<use href="#career-bar" style="--career-length: 300; --career-color: #f7bea1;"/>
<use href="#career-bar" style="--career-length: 200; --career-color: #c2d1d6;"/>

Пример инфографики с настраиваемыми барами разных размеров и цветов

Пример 3: Сложные анимации персонажей

Создайте живых персонажей с множеством анимаций:

Моргание глаз:

<symbol id="outlaw-1">
  <g class="eyelids" style="opacity: var(--eyelids-opacity, 1);">
    <!-- ... -->
  </g>
</symbol>
@keyframes blink {
  0%, 92% { --eyelids-opacity: 0; }
  93%, 94% { --eyelids-opacity: 1; }
  95%, 97% { --eyelids-opacity: 0.1; }
  98%, 100% { --eyelids-opacity: 0; }
}

Постукивание ногой:

<g class="outlaw-1-foot" style="
  transform-origin: bottom right; 
  transform: rotate(var(--foot-rotate));">
</g>
@keyframes tapping {
  0%, 60%, 100% { --foot-rotate: 0deg; }
  20% { --foot-rotate: -5deg; }
  40% { --foot-rotate: 2deg; }
}

Дрожание усов:

<g class="outlaw-1-tashe" style="
  transform: translateX(var(--jiggle-x, 0px));">
  <!-- ... -->
</g>
@keyframes jiggle {
  0%, 100% { --jiggle-x: 0px; }
  20% { --jiggle-x: -3px; }
  40% { --jiggle-x: 2px; }
  60% { --jiggle-x: -1px; }
  80% { --jiggle-x: 4px; }
}

Эффект моргания через анимацию прозрачности век

Эффект постукивания через анимацию вращения ноги

Эффект дрожания через анимацию перемещения усов

Комбинирование анимаций

Объедините несколько анимаций для сложных эффектов:

use[data-outlaw] {
  --blink-duration: 4s;
  --eyelids-opacity: 1;
  --foot-rotate: 0deg;
  --jiggle-x: 0px;
  animation: 
    blink var(--blink-duration) infinite var(--blink-delay),
    jiggle 1s ease-in-out infinite,
    tapping 1s ease-in-out infinite;
}

/* Разные задержки для каждого персонажа */
use[data-outlaw="1"] { --blink-delay: 1s; }
use[data-outlaw="2"] { --blink-delay: 2s; }
use[data-outlaw="3"] { --blink-delay: 3s; }

Важные рекомендации

  1. Всегда используйте fallback-значения:
    opacity: var(--eyelids-opacity, 1);
  2. CSS-переменные работают только с var():
    Элементы должны явно ссылаться на переменные через var().
  3. Проверяйте значения в DevTools:
    Используйте панель Computed Styles для отладки CSS-переменных.
  4. Inline-стили имеют приоритет:
    Помните о каскаде при комбинировании разных подходов.

Заключение

CSS-переменные служат мостом через барьер Shadow DOM, позволяя создавать сложные анимации для переиспользуемых SVG-символов. Этот подход делает код:

  • Чище — меньше дублирования
  • Легче — меньший размер файлов
  • Гибче — легкая настройка анимаций

Начните с простых анимаций и постепенно переходите к более сложным композициям, используя силу CSS-переменных для оживления ваших SVG-графиков.

2025