Грабли на чистом SVG

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

Предположим, вам понадобились SVG-иконки. Вы планируете перекрашивать их по наведению или взаимодействовать с ними как-то ещё, поэтому в качестве способа вставки выбираете не background-image, а use.

Подразумевается, что вы подготовили библиотеку иконок и вставили её на страницу.

Для примера возьму такой символ:

<symbol id="s-heart" viewBox="0 0 100 100">
  <path d="M100 34.976c0 8.434-3.635 16.019-9.423 21.274h0.048l-31.25 31.25c-3.125 3.125-6.25 6.25-9.375 6.25s-6.25-3.125-9.375-6.25l-31.202-31.25c-5.788-5.255-9.423-12.84-9.423-21.274 0-15.865 12.861-28.726 28.726-28.726 8.434 0 16.019 3.635 21.274 9.423 5.255-5.788 12.84-9.423 21.274-9.423 15.865 0 28.726 12.861 28.726 28.726z" fill="crimson"/>
</symbol>

Теперь иконку надо вставить в нужное место. Первым делом пишем такое:

<svg>
  <use xlink:href="#s-heart"/>
</svg>

Да, я знаю, что в теге нужно указывать пространство имен, чтобы все браузеры правильно понимали тег. Но до сих пор я не сталкивалась с проблемами в отображении такой конструкции, и мне всегда было интересно: а если его не указывать — что и где поломается? Всегда ли мы должны дописывать такой длинный хвост к такому короткому тегу?

viewBox уже задан в символе, поэтому его не нужно указывать в svg при вставке на страницу, потребуется задать только размеры иконки.

Задаем размеры:

SVG {
  width: 100px;
  height: 100px;
}

Конструкция работает во всех браузерах, которые поддерживают SVG.

Теперь нужно позаботиться о старых браузерах и добавить иконке фоновый PNG. Пишем что-нибудь типа:

SVG {
  width: 100px;
  height: 100px;
  background: url(heart.png);
}

Обычно фоновая картинка задается только для старых браузеров, например по классу .lt-ie9 SVG, но здесь я опустила этот момент для простоты.

Что получилось:

Ссылка на случай, если вы смотрите в IE8, и фрейм не отобразился: codepen.io/yoksel/pen/KnALd

Проверяем в 8-м IE и видим, что ничего не работает, причем сразу по нескольким причинам:

  1. SVG-элемент не существует с точки зрения IE8. Чтобы браузер начал догадываться о его существовании, нужно в тег svg добавить пространство имен, к которому он принадлежит: xmlns="http://www.w3.org/2000/svg".
  2. IE8 не понимает обращение к SVG-элементу по тегу — только по классу.
  3. SVG-элементу обязательно нужно добавить display: block или display: inline-block.

Исправляем код и получаем вот такое:

<!-- добавлены класс и пространство имен -->
<svg xmlns="http://www.w3.org/2000/svg" class="svg-icon">
  <use xlink:href="#s-heart"/>
</svg>
/* стили перенесены на класс, добавлен display: inline-block */
.svg-icon {
  display: inline-block;
  width: 100px;
  height: 100px;
  background: url(heart.png);
}

Результат:

Ссылка: codepen.io/yoksel/full/kABcb

SVG-элемент появился в IE8, только вместо векторного содержимого в нем будет фоновая картинка.

Конечно можно не заморачиваться, обернуть SVG в тег span, например, и задавать фон и размеры ему, но зачем, если можно обойтись без дополнительной разметки?

Вроде бы мы получили в IE8 SVG с фоллбеком, и все работает как надо, но проблемы на этом не заканчиваются. Если на странице есть HTML5-теги, верстка может разъехаться, если у элементов внутри SVG нет закрывающих парных тегов.

Пример такой разметки:

Ссылка: codepen.io/yoksel/pen/irvFb/

Вот так это демо будет выглядет в 8-м IE:

Html5-tags in IE8

Html5shiv.js не может корректно отработать, из-за чего HTML5-теги не могут стать блочными.

Решений тут два:

  1. Добавить в свой CSS явное указание display: block для HTML5-тегов.
  2. Закрывать все SVG-теги при вставке на страницу:

Например, есть символ, содержащий path:

<symbol id="s-heart" viewBox="0 0 100 100">
  <path d="M100 34.976c0 ... 28.726 28.726z"/>
</symbol>

Добавляем закрывающий тег:

<symbol id="s-heart" viewBox="0 0 100 100">
  <path d="M100 34.976c0 ... 28.726 28.726z"></path>
</symbol>

Аналогично надо сделать и для всех тегов use:

<svg xmlns="http://www.w3.org/2000/svg" class="svg-icon">
  <use xlink:href="#s-heart"></use>
</svg>

Исправленная разметка будет корректно работать во всех браузерах.

Надеюсь, эта статья сэкономит кому-то время в будущем, потому что известные грабли можно обойти не наступая. Да пребудет с вами сила SVG!

Зачем я написала плагин для GruntРежимы наложения и их фоллбеки
Наверх