SVG-спрайты
Мои предпочтения
Спрайт, в контексте веб-разработки, чаще всего, — один большой файл с графикой, получившийся в результате «сшития» нескольких маленьких графических файлов (иконок, элементов оформления). Это нужно для экономии количества запросов к серверу: меньше запросов — сайт работает и загружается быстрее. Сшивать в спрайт можно и растровую, и векторную графику.
Я расскажу о своём любимом способе работы с векторными спрайтами.
Работа с SVG (введение)
Не буду расхваливать SVG, причин его невероятной крутизны много и они неоднократно описаны. Поддержка начинается с IE9.
Источником векторных иконок (помимо дизайнеров) служат icomoon.io, flaticon.com, freepik.com/free-vectors и им подобные. Нарисовать самому можно в Adobe Illustrator или в Inkscape. Поскольку это обычный текстовой формат, редактировать его можно в текстовом редакторе.
Редакторы очень любят вставлять в код SVG-файлов служебную информацию, увеличивая вес файлов. Оптимизировать можно или он-лайн на jakearchibald.github.io/svgomg, или задачей для какого-либо таск раннера (см. ниже).
И да, SVG лучше иконочных шрифтов, ибо даёт больше возможностей и не является костылём).
У меня есть репозиторий со сводом рекомендаций для дизайнеров по работе с векторной графикой. Наиболее важные из них, актуальные для подготовки SVG-файлов к «сшивке» их в спрайт:
- Артборд подогнан по габариту фигуры или все однотипные артборды подогнаны под единый размер.
- Всё, что может быть слито в единую форму, слито.
- Убраны лишние объекты.
- Проведено сжатие.
SVG-спрайты
В подавляющем большинстве случаев, я использую такие спрайты для иконок. Мой любимый вариант основан на переиспользовании (symbol
и use
):
- Собираем один общий svg-файл со множеством
symbol
(элементы спрайта), имеющих своиid
. У тегаsvg
задаёмstyle="display:none"
. Смотреть пример. - Вставляем полученный спрайт в разметку страницы. (Я предпочитаю делать это с помощью javascript и localStorage, об этом ниже.)
- В разметке используем ссылки на
symbol
при помощиuse
. Смотреть пример.
Достоинства метода:
- чистый, читабельный код,
- управление с уровня CSS страницы (в том числе,
fill="currentColor"
), - кеширование в localStorage (спрайт загружается только единожды),
- доступность (можно добавить
title
).
Недостатки метода:
- управление с уровня CSS не полное: сложно управлять отдельными частями символа (имеющими свои CSS-классы), если он вставлен несколько раз,
- работает только с сервера (локального/удалённого — не важно), ибо использует localStorage.
Как собирать
Увы, в отличие от растровых спрайтов, он-лайн инструментов для сборки SVG-спрайта я не нашел (плохо искал?). Помимо ручной сборки (не-не-не-не, Девид Блейн, нет!) предложить могу только сборку с помощью Grunt/Gulp.
Вот репозиторий, собранный мной из своего старого стартового. В нём оставлена автоматизация, ответственная за сборку SVG-спрайта, сжатие javascript, запуск локального сервера и автообновление. После вызова команды grunt
в консоли, автомат соберёт спрайт, сожмёт javascript (нужен для работы с localStorage), запустит локальный сервер и откроет в браузере index.html
.
Для сжатия SVG использован imagemin (вот прекрасный аналог), для сборки спрайта использован grunt-svgstore. Уверен, что найти аналогичные задачи для Gulp не составит большого труда.
Как вставить спрайт в разметку
Информация о вставке несколько устарела. Сейчас я использую
svg > use
. Способов много. Поскольку полученный спрайт — строка текста, вставить её на страницу можно, как минимум, с уровня серверного программирования и с уровня автоматизации фронтенда.
Я для себя выбрал способ с javascript и localStorage, т.к. это не вызывает зависимостей ни от чего, кроме включенного javascript на стороне клиента: поддержка localStorage очень хорошая. Именно этот способ и используется в демонстрационном репозитории. Есть, впрочем, небольшая оговорка: localStorage имеет ограничение в 5 Мбайт на домен.
Способ описан в недавней статье Osvaldas Valutis и состоит в следующем: при срабатывании javascript происходит проверка: спрайт уже записан в localStorage? Если да, он берется оттуда и вставляется на страницу. Если нет, файл скачивается, записывается в localStorage и потом вставляется на страницу.
Скрипт снабжён переменной revision
, позволяющей контролировать кеширование спрайта. Если она изменится, спрайт будет перезагружен с сервера даже в том случае, если уже есть в localStorage.
Привожу листинг кода с комментариями:
;(function(window, document) {
'use strict';
var file = 'img/sprite.svg', // путь к файлу спрайта на сервере
revision = 1; // версия спрайта
if (!document.createElementNS || !document.createElementNS('http://www.w3.org/2000/svg', 'svg').createSVGRect) return true;
var isLocalStorage = 'localStorage' in window && window\['localStorage'\] !== null,
request,
data,
insertIT = function() {
document.body.insertAdjacentHTML('afterbegin', data);
},
insert = function() {
if (document.body) insertIT();
else document.addEventListener('DOMContentLoaded', insertIT);
};
if (isLocalStorage && localStorage.getItem('inlineSVGrev') == revision) {
data = localStorage.getItem('inlineSVGdata');
if (data) {
insert();
return true;
}
}
try {
request = new XMLHttpRequest();
request.open('GET', file, true);
request.onload = function() {
if (request.status >= 200 && request.status < 400) {
data = request.responseText;
insert();
if (isLocalStorage) {
localStorage.setItem('inlineSVGdata', data);
localStorage.setItem('inlineSVGrev', revision);
}
}
}
request.send();
} catch (e) {}
}(window, document));
В сжатом виде этот скрипт имеет очень небольшой размер.
Заключение
Если не нужен контроль с уровня CSS страницы, возможно лучшим решением будет вставлять небольшие (до 10 Кбайт) иконки прямо в CSS-файл, кодируя их в base64. В LESS даже встроенная функция для этого есть.