Тег svg в HTML: что это и как вставить на страницу

Тег <svg> (от английского scalable vector graphics, «масштабируемая векторная графика») создаёт на странице область, в которой рисуются фигуры, линии и текст по описанию, а не по пикселям. Рисунок не теряет чёткость при любом размере, поэтому тег подходит для значков, логотипов и схем. Тег парный: закрывающий </svg> обязателен. Пустой <svg /> со слэшем браузер тоже принимает, но рисовать в нём нечего.

Внутри svg пишутся свои теги: rect, circle, path, g, text, use и другие. Отдельными страницами в шпаргалке они не описаны, их разбирает раздел «Какие теги пишут внутри svg». Здесь собрано всё, что нужно знать о самом теге: как вставить, как задать размер, зачем нужны viewBox и xmlns, как красить и как сделать значок доступным.

HTML
<svg width="120" height="120" viewBox="0 0 120 120">
  <circle cx="60" cy="60" r="50" fill="tomato" />
</svg>

Тег svg в HTML: что это и чем он отличается от других тегов

Для браузера svg не обычный HTML-элемент. Разбор страницы помещает его и всё вложенное в отдельное пространство имён SVG. У такого элемента свой класс SVGSVGElement, а circle, path и g внутри считаются SVG-тегами со своими правилами.

При разборе страницы регистр названий атрибутов поправляется. Записанный строчными viewbox превращается в viewBox. Если же задать setAttribute("viewbox", ...) из скрипта, название останется строчным и атрибут не сработает.

Вызов document.createElement("svg") создаёт не svg, а неизвестный HTML-элемент. Разметка у него выглядит так же, но рисунка на экране нет. Для svg из скрипта нужен createElementNS с адресом пространства имён.

Внутри svg пустые теги можно закрывать слэшем, <circle /> принимается. В обычном HTML слэш у <div /> ничего не закрывает: следующий div окажется внутри предыдущего.

JavaScript
const NS = "http://www.w3.org/2000/svg";
const bad  = document.createElement("svg");     // HTMLUnknownElement
const good = document.createElementNS(NS, "svg"); // SVGSVGElement

Пример: что создаёт браузер

Результат

Кнопки создают один и тот же круг тремя способами. Класс и пространство имён измерены в вашем браузере.

Поддерживают все браузеры: по MDN, тег доступен везде с июля 2015 года.

Как вставить svg на страницу: прямо в код, img, object и фон

Один и тот же рисунок подключается четырьмя способами: написать код прямо в странице, подключить файл через img или object, либо взять файл фоном в CSS. От способа зависит, дотянутся ли до фигур внутри стили и скрипты страницы.

HTML
<!-- 1. код прямо в странице -->
<svg width="40" height="40" viewBox="0 0 40 40">
  <circle cx="20" cy="20" r="16" fill="currentColor" />
</svg>

<!-- 2. файл через img -->
<img src="icon.svg" width="40" height="40" alt="Значок">

<!-- 3. файл через object -->
<object data="icon.svg" type="image/svg+xml" width="40" height="40"></object>
CSS
/* 4. файл фоном */
.icon {
  width: 40px;
  height: 40px;
  background: url("icon.svg") no-repeat center / contain;
}

Пример: цвет текста и четыре способа

Результат

У всех четырёх рисунков один и тот же код с fill="currentColor". Цвет текста меняется у обёртки.

Сравнение способов

СпособСтили страницы доходят до фигурЦвет через currentColorКлик по фигуреОтдельный файл
Код в страницедадакаждая фигура получает свои событиянет, код записан в странице
imgнетнет, цвет из файласобытие получает сам imgда, браузер хранит его в кеше
objectнет, внутри свой документнет, цвет из файлавнутри документа свои событияда
Фон в CSSнетнет, цвет из файласобытие получает блок с фономда

Значки, которые должны менять цвет, лучше писать прямо в странице. Большие картинки без перекраски удобнее подключать через img: страница остаётся короче, а файл кешируется. Замеры svg через object и img есть на странице object.

Размер svg: width, height и значения по умолчанию

Без размеров и без viewBox svg занимает 300 на 150 пикселей, как canvas. Если задан viewBox, а размеров нет, svg растягивается на всю ширину контейнера, а высоту получает по пропорциям viewBox. Если viewBox нет, а ширина задана в CSS, высота остаётся 150 пикселей.

Атрибуты width и height принимают числа (пиксели, без единиц), проценты и длины с единицами. Если задан viewBox и только один из размеров, второй вычисляется по пропорциям.

HTML
<svg>...</svg>                              <!-- 300 на 150 -->
<svg viewBox="0 0 100 50">...</svg>          <!-- по ширине контейнера -->
<svg width="120" height="60">...</svg>        <!-- 120 на 60 -->
<svg viewBox="0 0 100 50" width="120">...</svg> <!-- 120 на 60, рисунок растянут -->

Пример: размер при разных атрибутах

Результат

Размер svg и масштаб рисунка измерены в рамке. Пунктир показывает границы svg.

viewBox и preserveAspectRatio: как рисунок подстраивается под область svg

Атрибут viewBox задаёт внутреннюю систему координат: четыре числа (x, y, ширина и высота) описывают, какой кусок рисунка виден в области svg. Если пропорции области и viewBox совпадают, масштаб равен ширине области, делённой на ширину viewBox. Меняя viewBox, рисунок приближают, отдаляют и сдвигают, а сами фигуры не трогают.

HTML
<svg width="160" height="80" viewBox="0 0 50 25">
  ...
</svg>

Пример: viewBox как область

Результат

Область svg всегда 160 на 80. Меняется только viewBox, а вердикт показывает, какие круги в области видно.

Когда пропорции области и viewBox разные, решает атрибут preserveAspectRatio. Значение по умолчанию xMidYMid meet сохраняет пропорции и показывает рисунок целиком по центру, поэтому сбоку остаётся пустое место. Значение slice закрывает рисунком всю область, лишнее обрезается. Значение none растягивает рисунок по каждой оси отдельно, и круг становится овалом. Без viewBox атрибут не действует.

HTML
<svg width="160" height="80" viewBox="0 0 50 50"
     preserveAspectRatio="xMidYMid slice">
  ...
</svg>

Пример: preserveAspectRatio

Результат

Квадратный рисунок 50 на 50 помещается в область 160 на 80. Масштаб по осям считает сам браузер.

xmlns в svg: когда он нужен

Атрибут xmlns="http://www.w3.org/2000/svg" объявляет пространство имён. Если svg записан прямо в HTML-страницу, атрибут не нужен: разбор страницы сам понимает, что внутри svg. Он обязателен там, где svg существует отдельным XML-документом: в файле .svg и в адресе data:, который вписывают в img или в CSS-фон. Без него файл не распознаётся как картинка.

В адресе data: есть вторая ловушка: символ # в адресе начинает фрагмент, и остальная часть строки отбрасывается. Поэтому в таком адресе # записывают как %23 или кодируют всю строку, либо берут base64.

CSS
.icon {
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'%3E%3Ccircle cx='5' cy='5' r='4' fill='%23c00'/%3E%3C/svg%3E");
}

Пример: когда картинка не загружается

Результат

Пять вариантов одного svg. Загрузку проверяет сам кадр.

Какие теги пишут внутри svg

Рисунок собирается из фигур, и каждая фигура пишется своим тегом. Все они работают только внутри svg. По умолчанию у фигур чёрная заливка и нет обводки, поэтому линия line без атрибута stroke на экране не видна.

HTML
<svg viewBox="0 0 200 120">
  <rect x="10" y="10" width="50" height="30" />
  <circle cx="90" cy="25" r="15" />
  <line x1="10" y1="80" x2="60" y2="52" stroke="#333" stroke-width="3" />
  <path d="M10 112 Q35 88 60 112" fill="none" stroke="#333" />
  <text x="90" y="110" font-size="16">svg</text>
</svg>

Пример: добавление тегов по одному

Результат

Кнопки включают и выключают теги. Под рисунком показан код последнего нажатого тега.

Основные теги внутри svg

ТегЧто делаетГлавные атрибуты
rectпрямоугольникx, y, width, height, rx
circleкругcx, cy, r
ellipseовалcx, cy, rx, ry
lineотрезокx1, y1, x2, y2, stroke
polyline, polygonломаная и многоугольникpoints
pathпроизвольная линия или фигураd
textтекстx, y, font-size
gгруппа: общие стили и преобразования для вложенных теговfill, stroke, transform
defs, symbolописания, которые сами не рисуютсяid, viewBox
useкопия по ссылкеhref
imageкартинка внутри svghref, x, y, width, height
title, descназвание и описание для программ чтения экрана и подсказкинет
styleтаблица стилейнет

Обычный HTML-тег внутри svg не работает. В примере выше div не остаётся внутри: разбор страницы выносит его наружу, и он выводится после рисунка. Чтобы показать HTML внутри svg, его оборачивают в foreignObject. Для надписей проще взять тег text.

Тег title внутри svg не имеет отношения к тегу title страницы: он задаёт название рисунка. Тег style внутри svg действует на всю страницу, а не только на этот рисунок, подробнее о нём на странице style.

Цвет и стили svg: fill, stroke и currentColor

Свойство fill задаёт заливку, stroke обводку, stroke-width толщину обводки. Их можно писать атрибутом тега или CSS-правилом. Если заданы оба способа, побеждает CSS-правило: атрибут проигрывает любому селектору. Свойства fill и stroke наследуются, поэтому их удобно задавать на g или на самом svg.

Значение currentColor берёт цвет из свойства color родителя. Так один значок меняет цвет вместе с текстом ссылки или кнопки. Всё это работает для svg, записанного в страницу. У файла через img и у фона свои цвета, страница на них не влияет.

CSS
.icon { color: seagreen; }
.icon circle { fill: currentColor; }
.icon:hover { color: tomato; }

Пример: откуда берётся цвет

Результат

Итоговый fill прочитан браузером: так видно, какой способ победил.

Тег svg строчный или блочный

По умолчанию svg строчный, display равен inline. Он ведёт себя как картинка: стоит в одной строке с текстом и сидит на базовой линии. Под базовой линией браузер резервирует место для нижних хвостов букв, поэтому под svg появляется зазор. Он равен примерно 5 пикселям при шрифте 15 пикселей, точное значение зависит от шрифта и измеряется в примере ниже. Зазор убирают значением display: block или vertical-align: middle. То же самое происходит у img.

CSS
svg {
  display: block; /* зазора под svg нет, но он больше не стоит в строке */
}

svg.inline-icon {
  vertical-align: middle; /* остаётся в строке, зазора нет */
}

Пример: зазор под svg

Результат

Красная рамка показывает зазор: высота рамки минус высота svg.

use, symbol и defs: один рисунок много раз

Описание, записанное внутри symbol или defs, само не рисуется. Тег use с ссылкой href="#id" рисует копию. Так собирают спрайт значков: описание записано на странице один раз, а копий может быть сколько угодно, и у каждой свой размер. Цвет задаётся через currentColor.

Спрайт прячут, чтобы он не занимал место. Рисунок из symbol при этом работает и с display: none. Но градиент из спрайта с display: none в проверке не нарисовался. Надёжнее прятать спрайт нулевым размером: width="0" height="0" и position: absolute.

HTML
<svg width="0" height="0" style="position:absolute">
  <symbol id="star" viewBox="0 0 24 24">
    <path fill="currentColor" d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01z" />
  </symbol>
</svg>

<svg width="24" height="24"><use href="#star" /></svg>
<svg width="64" height="64" style="color:teal"><use href="#star" /></svg>

Пример: три копии одного symbol

Результат

Кнопка «Убрать symbol» удаляет описание: копии остаются на странице, но рисовать им нечего.

Доступность svg: title, role и aria-hidden

Программы чтения экрана воспринимают svg как картинку. Если значок только украшает текст рядом, ему добавляют aria-hidden="true", и он пропускается. Если значок несёт смысл, ему дают название: атрибутом aria-label или первым вложенным тегом title, и добавляют role="img", чтобы svg точно считался картинкой.

Для кнопки или ссылки, в которой есть только значок, название нужно кнопке или ссылке: без него она остаётся безымянной. Подробнее о кнопках на странице button.

HTML
<button type="button" aria-label="Закрыть">
  <svg aria-hidden="true" width="16" height="16" viewBox="0 0 16 16">
    <path d="M2 2l12 12M14 2L2 14" stroke="currentColor" stroke-width="2" />
  </svg>
</button>

Проверка: что видит программа чтения экрана

РазметкаЧто видит программа чтения экрана (по снимку браузера)
<button><svg>...</svg></button>кнопка без названия, внутри безымянная картинка
<button><svg aria-hidden="true">...</svg> Закрыть</button>кнопка «Закрыть», значок пропущен
<a><svg role="img" aria-label="Домой">...</svg></a>ссылка «Домой»
<a><svg role="img"><title>Поиск</title>...</svg></a>ссылка «Поиск»
<p><svg>...</svg></p>безымянная картинка
<p><svg><title>Декор</title>...</svg></p>картинка «Декор»: название взято из title даже без role

Атрибуты тега svg

Тег принимает глобальные атрибуты (id, class, style, role, aria-*) и собственные, перечисленные в таблице. Обычные свойства вроде fill и stroke тоже можно писать атрибутами, но у них приоритет слабее CSS.

АтрибутЧто делаетЗначение по умолчанию
width, heightразмер области svgauto: 300 на 150 или по viewBox
viewBoxкакая часть рисунка видна в области svgнет
preserveAspectRatioкак рисунок вписывается в область с другими пропорциямиxMidYMid meet
xmlnsпространство имён: нужен в файле .svg и в адресе data:, в HTML не нуженнет
x, yположение вложенного svg; у внешнего svg не действуют0
version, baseProfileустарели, на вывод не влияют: MDN советует не использовать в новых проектахнет

Полное описание есть в MDN и в спецификации SVG 2.

Частые ошибки с тегом svg

Почти все ошибки с svg от того, что разбирается он не по правилам HTML.

ОшибкаЧто получитсяКак исправить
document.createElement("svg")Неизвестный HTML-элемент, рисунка нетcreateElementNS("http://www.w3.org/2000/svg", "svg")
<div> или <p> прямо внутри svgРазбор страницы выносит тег наружу, он оказывается после рисункаОбернуть в foreignObject или взять text
svg без размеров и без viewBoxРисунок 300 на 150 пикселейЗадать width и height или viewBox
Файл или data:-адрес без xmlnsКартинка не загружаетсяДобавить xmlns="http://www.w3.org/2000/svg"
Символ # в data:-адресеКартинка не загружаетсяЗаписать как %23 или взять base64
Перекрасить значок из img стилями страницыЦвет не меняетсяЗаписать svg в страницу или задать цвет в самом файле
setAttribute("viewbox", ...)Атрибут не срабатываетПисать viewBox с большой B
Зазор под значком в строкеЛишние несколько пикселей под svgdisplay: block или vertical-align: middle
Кнопка только со значком, без названияПрограмма чтения экрана видит безымянную кнопкуaria-label у кнопки и aria-hidden="true" у значка
Категория
Поделиться в социальных сетях
Основные HTML-теги
Семантические теги HTML
Заголовки и абзацы
Теги для форматирования текста
Тег гиперссылки HTML
HTML-теги таблицы
Списки в HTML
Теги для форм
Мультимедиа и изображения
Интерактивные и служебные теги
Устаревшие HTML-теги

Отправить комментарий

0 Комментарии

Отправить комментарий (0)

#buttons=(Хорошо) #days=(20)

Мы используем файлы cookie для улучшения работы сайта. Подробнее
Хорошо
×