Я много рассказывал о теге <use> в SVG и использовал его для вывода иконок. Прелесть в том, что с помощью <use> можно ссылаться на часть SVG и выводить только её. Это позволяет использовать схему «много изображений за один запрос, потому что это суперэффективно», которую раньше решали с помощью CSS-спрайтов и иконочных шрифтов.
Перевод статьи «How SVG Fragment Identifiers Work» от Криса Койера.
Но <use> — это инлайновый SVG. Он не поможет, если вы хотите использовать часть SVG в теге <IMG> или в background-image. Вот тут и появляются идентификаторы фрагментов.
Подготовка SVG-спрайта
Один из способов — привести SVG (давайте называть его просто «спрайт») к виду обычного CSS-спрайта.
Мы специально делаем это именно так, чтобы потом быть в состоянии использовать значения viewBox, для вывода отдельных фрагментов, как мы привыкли это делать в обычных спрайтах.
В этом небольшом демо-спрайте используется три иконки. Каждая иконка имеет размер 32×32. Весь спрайт — 32×96. Давайте посмотрим, каким будет viewBox для отдельных частей спрайта:
ViewBox всего спрайта — 0 0 32 96
ViewBox первой иконки — 0 0 32 32
ViewBox второй иконки — 0 32 32 32
ViewBox третьей иконки — 0 64 32 32
Атрибуты viewBox указывают на координаты начала слева, координаты начала сверху, ширину и высоту. Обратите внимаение, что каждый раз позиция начала сверху сдвигается на 32. Мы просто показываем другую часть спрайта.
Добавление viewBox в сам SVG
Вы можете указать эти значения viewBox для каждого элемента <view>, внутри SVG.
<view id="icon-clock-view" viewBox="0 0 32 32" />
<view id="icon-heart-view" viewBox="0 32 32 32" />
<view id="icon-arrow-right-view" viewBox="0 64 32 32" />
Теперь мы можем использовать эти части в других местах. Элементы <view> могут быть самостоятельными, как в примере выше, или могут оборачивать другие элементы. В этом случае viewBox отобразится, если совпадает ID.
<!-- Этот viewBox отобразится, если идентификатор будет #match-me. -->
<view id="match-me" viewBox="0 64 32 32">
<rect ...>
</view>
Демо в спецификации.
Синтаксис в HTML
Применять значения viewBox в SVG-вставленном-как-IMG вы можете следующим образом:
<!-- top icon -->
<img src="sprite.svg#svgView(viewBox(0, 0, 32, 32))" alt="">
Или, если вы уже настроили view-элементы, то можете ссылаться на них по ID:
<!-- middle icon -->
<img src="sprite.svg#icon-heart-view" alt="">
Синтаксис в CSS
Вы можете указывать требуемое значение viewBox прямо в пути к изображению в CSS
.icon-clock {
background: url("sprite.svg#svgView(viewBox(0, 0, 32, 32))") no-repeat;
}
Или, опять же, ссылаться на них по ID:
.icon-clock {
background: url(sprite.svg#icon-clock-view) no-repeat;
}
Хотя… Если вы используете SVG-спрайт таким образом и у вас пошло что-то не так, то вы можете просто использовать способ из обычных спрайтов:
.icon-heart {
background: url("sprite.svg") no-repeat;
background-size: 32px 96px;
background-position: 0 -32px;
}
Я хочу складывать иконки друг на друга
Если у всех иконок одинаковый viewBox и вы хотите просто показывать и скрывать их, когда это необходимо, то это может быть чуть легче.
Поместите их все в одно место (или используйте какой-нибудь сборщик). Вот, я кладу каждую иконку в группу и указывают уникальный ID.
Трюк с отображением нужной иконки заключается в том, чтобы скрыть все иконки и отобразить ту, чей ID совпадает с указанным. Это всё можно сделать на CSS, потому что у нас есть псевдокласс :target.
SVG со всем этим будет выглядеть так:
<defs>
<style>
g {
display: none;
}
g:target {
display: inline;
}
</style>
</defs>
<g id="icon-clock">
<path d="M20.6,23.3L14,16.7V7.9h4v7.2l5.4,5.4L20.6,23.3z M16-0.1c-8.8,0-16,7.2-16,16s7.2,16,16,16s16-7.2,16-16S24.8-0.1,16-0.1z
M16,27.9c-6.6,0-12-5.4-12-12s5.4-12,12-12s12,5.4,12,12S22.6,27.9,16,27.9z"/>
</g>
<g id="icon-heart">
<path d="M32,11.2c0,2.7-1.2,5.1-3,6.8l0,0L19,28c-1,1-2,2-3,2s-2-1-3-2L3,18c-1.9-1.7-3-4.1-3-6.8C0,6.1,4.1,2,9.2,2
c2.7,0,5.1,1.2,6.8,3c1.7-1.9,4.1-3,6.8-3C27.9,1.9,32,6.1,32,11.2z"/>
</g>
<g id="icon-arrow-right">
<path d="M32,15.9l-16-16v10H0v12h16v10L32,15.9z"/>
</g>
Поддержка браузеров
Можно посмотреть поддержку в Can I Use, но не всё так просто, потому что некоторые браузеры поддерживают только использование идентификаторов в HTML, а у некоторых какие-то проблемы.
Вот основные моменты поддержки браузеров, которые я могу отметить:
- В Firefox всё работает правильно.
- В IE11 тоже. У IE 9 и 10 небольшие проблемы с background-position, но, в целом, всё неплохо.
- В последних Chrome/Opera всё работает.
- Единственное что работает в iOS 8.1 — это ссылка на view внутри img (смотри сноску ниже).
- Для Android 4.4 подходит только background-position (который вообще не использует идентификаторы). В Android 5 всё нормально.
Комментарий переводчика:
Не знаю где и как проверял автор статьи поддержку в iOS, но, судя по BrowserStack, в iOS9 работает только вывод через background-position. Буду рад, если кто-нибудь потратит пару минут на переход к демке и отпишется как обстоят дела на самом деле.