Открой любой .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);
}
Никакого 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
Ссылки
-
MDN: currentColor — keyword разрешается в computed-значение
colorродителя. В режиме<img>SVG изолирован от CSS родительского документа, поэтомуcurrentColorрезолвится вcolorкорня самого SVG-документа (по умолчанию — чёрный). ↩ -
MDN: preserveAspectRatio — атрибут управляет тем, как содержимое viewBox масштабируется, если соотношение сторон не совпадает с
width/height. Девять значений выравнивания (xMinYMin,xMidYMid,xMaxYMaxи т. д.) × два режима (meet— вписать целиком,slice— заполнить и обрезать). ↩ -
SVG Integration — Processing Modes — спецификация W3C. SVG, загруженный через
<img>,<picture>,background-image,border-image, переводится вsecure static mode(илиsecure animated mode, если есть SMIL-анимации): скрипты заблокированы, внешние ресурсы не загружаются, интерактивные обработчики не работают. Через<object>,<iframe>, inline — режимdynamic interactive, всё включено. ↩