Как работает SVG ID?

Перевод статьи «How SVG Fragment Identifiers Work» от Криса Койера.

Я много рассказывал о теге <use> в SVG и использовал его для вывода иконок. Прелесть в том, что с помощью <use> можно ссылаться на часть SVG и выводить только её. Это позволяет использовать схему «много изображений за один запрос, потому что это суперэффективно», которую раньше решали с помощью CSS-спрайтов и иконочных шрифтов.

Но <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, а у некоторых какие-то проблемы.

Это моя тестовая страница:

See the Pen SVG Fragment Identifiers in HTML and CSS by Chris Coyier (@chriscoyier) on CodePen.

Вот основные моменты поддержки браузеров, которые я могу отметить:

  • В Firefox всё работает правильно.
  • В IE11 тоже. У IE 9 и 10 небольшие проблемы с background-position, но, в целом, всё неплохо.
  • В последних Chrome/Opera всё работает.
  • Единственное что работает в iOS 8.1 — это ссылка на view внутри img.
  • Для Android 4.4 подходит только background-position (который вообще не использует идентификаторы). В Android 5 всё нормально.
Комментариев ещё нет. Оставьте первый!