Спрайт, в контексте веб-разработки, чаще всего, — один большой файл с графикой, получившийся в результате «сшития» нескольких маленьких графических файлов (иконок, элементов оформления). Это нужно для экономии количества запросов к серверу: меньше запросов — сайт работает и загружается быстрее. Сшивать в спрайт можно и растровую, и векторную графику.

Я расскажу о своём любимом способе работы с векторными спрайтами.

Работа с SVG (введение)

Не буду расхваливать SVG, причин его невероятной крутизны много и они неоднократно описаны. Поддержка начинается с IE9.

Источником векторных иконок (помимо дизайнеров) служат icomoon.io, flaticon.com, freepik.com/free-vectors и им подобные. Нарисовать самому можно в Adobe Illustrator или в Inkscape. Поскольку это обычный текстовой формат, редактировать его можно в текстовом редакторе.

Редакторы очень любят вставлять в код SVG-файлов служебную информацию, увеличивая вес файлов. Оптимизировать можно или он-лайн на jakearchibald.github.io/svgomg, или задачей для какого-либо таск раннера (см. ниже).

И да, SVG лучше иконочных шрифтов, ибо даёт больше возможностей и не является костылём).

У меня есть репозиторий со сводом рекомендаций для дизайнеров по работе с векторной графикой. Наиболее важные из них, актуальные для подготовки SVG-файлов к «сшивке» их в спрайт:

SVG-спрайты

В подавляющем большинстве случаев, я использую такие спрайты для иконок. Мой любимый вариант основан на переиспользовании (symbol и use ):

  1. Собираем один общий svg-файл со множеством symbol (элементы спрайта), имеющих свои id . У тега svg задаём style="display:none" . Смотреть пример.
  2. Вставляем полученный спрайт в разметку страницы. (Я предпочитаю делать это с помощью javascript и localStorage, об этом ниже.)
  3. В разметке используем ссылки на symbol при помощи use . Смотреть пример.

Достоинства метода:

Недостатки метода:

Как собирать

Увы, в отличие от растровых спрайтов, он-лайн инструментов для сборки SVG-спрайта я не нашел (плохо искал?). Помимо ручной сборки (не-не-не-не, Девид Блейн, нет!) предложить могу только сборку с помощью Grunt/Gulp.

Вот репозиторий, собранный мной из своего старого стартового. В нём оставлена автоматизация, ответственная за сборку SVG-спрайта, сжатие javascript, запуск локального сервера и автообновление. После вызова команды grunt в консоли, автомат соберёт спрайт, сожмёт javascript (нужен для работы с localStorage), запустит локальный сервер и откроет в браузере index.html .

Для сжатия SVG использован imagemin (вот прекрасный аналог), для сборки спрайта использован grunt-svgstore. Уверен, что найти аналогичные задачи для Gulp не составит большого труда.

Как вставить спрайт в разметку

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

Я для себя выбрал способ с 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 даже встроенная функция для этого есть.

Буду рад обсуждению.