Назад к блогу
9 мин. чтения

SVG — это не картинка, это код

SVG — не картинка с прозрачностью, а XML-документ, который браузер рендерит как графику. Разбираем, что это даёт дизайнеру и no-code разработчику.
Содержание
  1. Две стратегии использования
  2. Как файл
  3. Inline
  4. Когда что выбирать
  5. Что даёт inline (и чего не может файл)
  6. 1. Перекраска через currentColor
  7. 2. Анимация через CSS
  8. 3. Доступ из JavaScript
  9. viewBox — почему иконка «едет»
  10. SVG в платформах
  11. Три мелочи, которые часто упускают
  12. Оптимизация
  13. Безопасность
  14. Доступность
  15. Чеклист: перед вставкой SVG на сайт
  16. Источники и где дальше копать

Открой любой .svg файл в текстовом редакторе. Notepad, VS Code — без разницы. Что увидишь? XML — код, который читается и редактируется:

<svg width=«24» height=«24» viewBox=«0 0 24 24» xmlns=«http://www.w3.org/2000/svg»>
  <circle cx=«12» cy=«12» r=«10» fill=«currentColor»/>
</svg>

↑ этот круг — рендер кода выше. Браузер прочитал XML, нарисовал графику.

Это — самая важная мысль, которую я хочу, чтобы ты унёс из поста. SVG — это не векторная картинка с прозрачностью, как думают многие. Это XML-документ, который браузер рендерит как графику.

Звучит как нюанс. На самом деле — это меняет многое. Дизайнер, который воспринимает SVG как «просто формат картинки», упускает половину возможностей. No-code разработчик, который вставляет SVG только как файл, отрезает себе интерактивные возможности: перекраску, анимации и другие эффекты.

Разбираемся, что это меняет на практике.


Две стратегии использования

SVG вставляется на сайт двумя принципиально разными способами. И от выбора зависит, что ты с ним сможешь делать дальше.

Как файл

Изображение <img> в HTML:

<img src=«/icons/heart.svg» alt=«Like» />

Фоновое изображение background-image в CSS:

.button {
  background-image: url(«/icons/heart.svg»);
}

Просто. Кешируется браузером. Работает в конструкторах сайтов через стандартный upload картинки. Для статических декоративных иконок — идеально.

Минус один, но фундаментальный: для CSS это «чёрный ящик». Браузер обрабатывает SVG-файл как изолированный документ — так же, как PNG или JPEG. CSS не имеет доступа к содержимому файла. Хочешь, чтобы иконка меняла цвет при ховере? Придётся держать вторую копию файла в нужном цвете и скрывать одно изображение / показывать второе — что тяжелее чем вставить inline SVG.

Inline

<svg width=«24» height=«24» viewBox=«0 0 24 24»>
  <circle cx=«12» cy=«12» r=«10» fill=«currentColor» />
</svg>

SVG вставляется прямо в HTML, становится частью DOM. И вот тут начинается интересное: каждый элемент внутри SVG (<circle>, <path>, <rect>) — это полноценный DOM-элемент. К нему применяется CSS, навешиваются события в JS, его можно анимировать.

Минусы: дублируется в каждом месте, где используется. Не кешируется отдельно. HTML становится чуть тяжелее.

Когда что выбирать

Простое правило:

  • Нужна только отрисовка (статическая иконка, illustration в углу) → файл
  • Нужна перекраска (иконка меняет цвет при ховере, подхватывает тему сайта) → inline
  • Нужна анимация (бургер раскрывается, стрелка крутится, что-то реагирует) → inline
  • Нужна интерактивность (клик на регион SVG-карты, наведение на сектор графика) → inline

Есть ещё гибридный вариант — SVG-спрайт с <use>, когда одна иконка переиспользуется в десятках мест. Это отдельная тема, в этот пост не помещается.


Что даёт inline (и чего не может файл)

1. Перекраска через currentColor

Если в SVG поставить fill="currentColor" или stroke="currentColor", иконка наследует цвет текста родителя. Один файл — бесконечная палитра через CSS: переменные темы, ховеры, активные состояния.

Важно: currentColor работает только в inline SVG. В <img src="..."> — нет, потому что CSS внешнего документа не достаёт внутрь файла (тот самый «чёрный ящик» из прошлого раздела).1

<button class=«like-btn»>
  <svg width=«24» height=«24» viewBox=«0 0 24 24»>
    <path
      d=«M12 21s-7-4.35-7-10a4 4 0 0 1 7-2.65A4 4 0 0 1 19 11c0 5.65-7 10-7 10z»
      fill=«currentColor»
    />
  </svg>
  Like
</button>
.like-btn {
  color: #333;
  transition: color 0.2s;
}
.like-btn:hover {
  color: red; /* иконка тоже станет красной */
}
← наведи курсор на кнопку

Один SVG. Меняешь только CSS — иконка перекрашивается. Никаких копий heart-red.svg, heart-blue.svg, heart-grey.svg.

Это решает задачи, ради которых дизайнеры обычно делают по 5 копий одной иконки. Поэтому — must-know.

2. Анимация через CSS

Поскольку каждая фигура внутри SVG — это DOM-элемент, к нему применяется любой CSS, включая transition и @keyframes.

Минимальный пример — стрелка, которая поворачивается:

<svg width=«24» height=«24» viewBox=«0 0 24 24» class=«arrow»>
  <path d=«M9 6l6 6-6 6» stroke=«currentColor» stroke-width=«2» fill=«none» />
</svg>
.arrow {
  transition: transform 0.3s;
}
.expanded .arrow {
  transform: rotate(90deg);
}
← CSS-анимация, без JS

Никакого JS, никаких библиотек. Просто CSS на SVG-элементе. Так делается анимация бургер-меню, состояния чекбоксов, спиннеры загрузки и многое другое.

3. Доступ из JavaScript

SVG-элементы выбираются через document.querySelector, к ним навешиваются обработчики событий, меняются атрибуты. Это открывает дорогу для интерактивных карт, графиков, диаграмм.

Не буду углубляться — просто знай, что эта дверь открыта.


viewBox — почему иконка «едет»

Один атрибут, из-за которого иногда ломается отображение SVG.

Проще всего объяснить так: viewBox — это crop-фрейм для внутреннего холста SVG. Представь, что внутри SVG-файла лежит бесконечная Figma-страница в условных единицах, а viewBox — это рамка фрейма, которая говорит браузеру: «вот этот кусок холста — показывай, остальное обрезай».

Четыре значения внутри — min-x min-y width height: левый-верхний угол рамки и её размеры. Атрибут viewBox="0 0 24 24" означает рамку, которая начинается в точке (0, 0) и имеет размер 24×24 условные единицы. Это не пиксели — это внутренние координаты SVG, как координаты внутри Figma-фрейма.

А вот width и height на самом теге <svg> (или CSS-размеры) — это физический размер картинки на странице. Браузер берёт содержимое внутри viewBox-рамки и растягивает его до этого физического размера. Поэтому SVG с viewBox="0 0 24 24" и width="48" будет выглядеть в два раза больше — без потери качества, потому что это вектор.

Если коротко: viewBox = что показывать, width/height = на каком размере показывать. Два разных слоя, которые часто путают.

Если после экспорта из Figma иконка едет, обрезается или ведёт себя странно — проблема почти всегда в viewBox или в preserveAspectRatio.2 Открой SVG в редакторе и посмотри глазами на эти атрибуты.

Подробности — на MDN: viewBox.


SVG в платформах

Коротко по основным:

Webflow. Файлом — через стандартный image asset (картинка как картинка). Inline — через блок HTML Embed: копируешь SVG-код, вставляешь, иконка становится частью DOM и доступна для CSS.

Framer.

  • Как картинку — простой drag&drop SVG-файла на холст. Framer положит его как обычное изображение, перекраска и анимация частей недоступны.
  • Как код — Code Component на React. Самый гибкий путь: можно прокидывать пропы, делать состояния, сложные анимации. Порог входа выше — нужно понимать React.

Tilda. В основном — работа с SVG как с файлом (через стандартную загрузку изображения). Inline возможен через блок T123 (HTML-код), но интерфейс Tilda не помогает: код пишется и редактируется руками. Перекраска через currentColor сработает, если SVG вставлен именно через T123, а не как картинка.

Общее правило: если платформа умеет вставлять произвольный HTML — она умеет inline SVG.


Три мелочи, которые часто упускают

Оптимизация

Figma, Sketch, Illustrator при экспорте SVG щедро добавляют мусор: лишние <defs>, пустые группы, метаданные, ID, ненужные атрибуты. Иконка из Figma на 5 КБ после оптимизации легко становится 1 КБ. Та же иконка, та же визуальная информация — просто без лишнего.

Гонять каждый файл через SVGOMG перед заливкой на сайт — must-have. Это веб-версия SVGO: открываешь, кидаешь файл, скачиваешь оптимизированный. 30 секунд на иконку.

Безопасность

SVG — это код. Значит, внутри может быть <script>. Реальный JavaScript, который выполнится в браузере.

Что это значит на практике: не вставляй SVG из непроверенных источников через inline или Embed-блок. Особенно если на твоём сайте есть аплоад файлов от пользователей (аватары, например). SVG от анонимного юзера — потенциальный вектор XSS-атаки.

Файлом (<img src="...">) — безопаснее: браузер по спецификации SVG переводит такой файл в secure static/animated mode — отключены скрипты, внешние ресурсы и интерактив.3 Inline — только то, что ты сам проверил глазами в редакторе.

Доступность

Если SVG используется как смысловая иконка (а не декоративная), добавь <title> внутрь:

<svg
  width=«24»
  height=«24»
  viewBox=«0 0 24 24»
  role=«img»
  aria-labelledby=«delete-icon-title»
>
  <title id=«delete-icon-title»>Удалить</title>
  <path d=«...» />
</svg>

Скринридер прочитает «Удалить», незрячий пользователь поймёт, на что нажимает. Одна строчка кода — и проект становится взрослее.

Декоративные SVG, наоборот, скрываются от скринридеров через aria-hidden="true".


Чеклист: перед вставкой SVG на сайт

  • Нужна перекраска или анимация? → inline. Нет → можно файлом
  • Прогнан через SVGOMG?
  • viewBox на месте? width/height не захардкожены без необходимости?
  • Для смысловых иконок — есть <title> внутрь SVG?
  • У <title> стоит уникальный id, а на <svg>role="img" и aria-labelledby с этим id?
  • Для декоративных иконок — на <svg> стоит aria-hidden="true"?
  • Если SVG из внешнего источника — открыл в редакторе и проверил, что нет <script>?
  • Если используется currentColor — родительский элемент задаёт color корректно?

Источники и где дальше копать

  • MDN: SVG — главный канонический справочник
  • MDN: viewBox — про систему координат
  • MDN: Using SVG in HTML — inline-стратегии и тонкости
  • SVGOMG — веб-оптимизатор от Jake Archibald

Ссылки

  1. MDN: currentColor — keyword разрешается в computed-значение color родителя. В режиме <img> SVG изолирован от CSS родительского документа, поэтому currentColor резолвится в color корня самого SVG-документа (по умолчанию — чёрный).

  2. MDN: preserveAspectRatio — атрибут управляет тем, как содержимое viewBox масштабируется, если соотношение сторон не совпадает с width/height. Девять значений выравнивания (xMinYMin, xMidYMid, xMaxYMax и т. д.) × два режима (meet — вписать целиком, slice — заполнить и обрезать).

  3. SVG Integration — Processing Modes — спецификация W3C. SVG, загруженный через <img>, <picture>, background-image, border-image, переводится в secure static mode (или secure animated mode, если есть SMIL-анимации): скрипты заблокированы, внешние ресурсы не загружаются, интерактивные обработчики не работают. Через <object>, <iframe>, inline — режим dynamic interactive, всё включено.