Pull to refresh

Векторная замена спрайтам — имплантируем SVG в CSS

Reading time 4 min
Views 44K
Не так давно компания, в которой я работаю, наконец-то окончательно отказалась от поддержки IE8 и, как следствие, я вплотную занялся вопросом перехода с растровых иконок на векторные. Основные плюсы SVG — это масштабирование, малый вес и возможность стилизации через CSS.

Сначала я попробовал воспользоваться техникой спрайтов, просто использовав вместо растра вектор, но тут возникло две проблемы:
  • Масштабирование. При произвольных размерах элементов спрайта для того, чтобы его точно отпозиционировать, приходится танцевать с бубном. И при изменении размера самого спрайта (например, при добавлении нового элемента) все может поползти.
  • Возможность стилизации посредством CSS отсутствует, потому что физически SVG-картинки в HTML-коде нет.


Тут я вспомнил про интеграцию картинок в CSS посредством кодирования оных base64 и использования data-uri. А с SVG все гораздо проще.Поскольку SVG-изображение — это XML-файл, то для него даже base64 не требуется, достаточно указать mime-тип как data:image/svg+xml и вставить содержимое SVG-файла одной строкой.

Возьмем, к примеру, иконку корзины:

image

Ее код выглядит примерно так:

<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" version="1.1" viewBox="0 0 1850 1635" xmlns:xlink="http://www.w3.org/1999/xlink">
 <g id="icon__cart">
  <path fill="#101010" d="M1254 1163l-1203 0c-26,0 -51,-25 -51,-51l0 -131c0,-23 22,-51 51,-51l1075 0c22,0 36,-13 44,-30l96 -192c4,-9 1,-12 -8,-12l-1207 0c-22,0 -51,-25 -51,-51l0 -131c0,-23 23,-51 51,-51l1298 0c27,0 46,-13 56,-33l200 -401c9,-18 20,-29 41,-29l182 0c19,0 29,7 18,29l-554 1111c-5,10 -19,23 -38,23z"/>
  <circle fill="#101010" cx="207" cy="1453" r="181"/>
  <circle fill="#101010" cx="1062" cy="1453" r="181"/>
 </g>
</svg>

Соответственно, использование ее в качестве фона в data-uri будет выглядеть так:

.element_whis_svg_background {
  background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" version="1.1" viewBox="0 0 1850 1635" xmlns:xlink="http://www.w3.org/1999/xlink">...</svg>');
}

Пробуем. В Хроме и Опере все замечательно, а вот в IE9-10-11, Safari, и, как ни странно, Firefox — фоновая картинка не отображается, они не понимают такой формат записи. Лезем искать, в чем проблема и выясняем, что для IE и прочих для содержимого SVG-файла надо выполнить URI-кодирование строки по стандарту RFC 3986. Кодируем, получаем вот такую конструкцию:

%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201850%201635%22%3E%3Cg%20fill%3D%22%23101010%22%3E%3Cpath%20d%3D%22M1254%201163H51c-26%200-51-25-51-51V981c0-23%2022-51%2051-51h1075c22%200%2036-13%2044-30l96-192c4-9%201-12-8-12H51c-22%200-51-25-51-51V514c0-23%2023-51%2051-51h1298c27%200%2046-13%2056-33l200-401c9-18%2020-29%2041-29h182c19%200%2029%207%2018%2029l-554%201111c-5%2010-19%2023-38%2023z%22%2F%3E%3Ccircle%20cx%3D%22207%22%20cy%3D%221453%22%20r%3D%22181%22%2F%3E%3Ccircle%20cx%3D%221062%22%20cy%3D%221453%22%20r%3D%22181%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E

Подставляем ее в background, проверяем:

.element_whis_svg_background {
  background: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2 ... svg%3E');
} 

Ура, все работает! Нюанс — кодировку в данном случае указывать не нужно. Если указать — то перестанет работать в IE.

Ну и, наконец, для того, чтобы внешний вид иконки можно было настраивать, используем любой препроцессор (я использую LESS, но это не принципиально) и оформим наш класс иконки как примесь (mixin). Для того, чтобы можно было менять цвет заливки, находим в кодированной строке атрибут fill, там будет что-то типа:

 fill%3D%22%23101010%22

То, что находится между %23 и %22 — и есть искомый код цвета, на место которого надо подставить переменную. В итоге получим следующее:

.icon__cart(@width, @height, @fill) {
  content: '';
  display: block;
  width: @width;
  height: @height;
  background-size: contain;
  background-repeat: no-repeat;
  background: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201850%201635%22%3E%3Cg%20fill%3D%22%23@{fill}%22%3E%3Cpath%20d%3D%22M1254%201163H51c-26%200-51-25-51-51V981c0-23%2022-51%2051-51h1075c22%200%2036-13%2044-30l96-192c4-9%201-12-8-12H51c-22%200-51-25-51-51V514c0-23%2023-51%2051-51h1298c27%200%2046-13%2056-33l200-401c9-18%2020-29%2041-29h182c19%200%2029%207%2018%2029l-554%201111c-5%2010-19%2023-38%2023z%22%2F%3E%3Ccircle%20cx%3D%22207%22%20cy%3D%221453%22%20r%3D%22181%22%2F%3E%3Ccircle%20cx%3D%221062%22%20cy%3D%221453%22%20r%3D%22181%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E');
} 

Используется данная примесь следующим образом (образец произвольный):

.block-whis-icon._cart {
  ...;

  &::before {
    .icon__cart(30px, 20px, '1d9fbb');
    ...;
  } 
} 

Вот, собственно, и все. LESS- (SASS, Stylus, etc.) файлик с такими примесями отлично заменяет спрайт.

Для оптимизации и кодирования SVG я использовал GULP, плагины gulp-svgo и gulp-data-uri-stream. Да, этот метод дает возможность менять лишь размеры иконки, цвет заливки и обводки, но в большинстве своем этого вполне достаточно.
Tags:
Hubs:
+15
Comments 27
Comments Comments 27

Articles