Stack — спрайт здорового человека
firefoxicК сожалению почти везде рассказывают только про символьный спрайт. В действительности видов спрайтов есть минимум… пять! И Артур Трифонов собрал тестовую страничку для сравнения возможностей всех пяти видов во всех четырёх возможных вариантах использования:
- два из разметки (
img
иuse
), которые нужны например для логотипа сайта; - и два из стилей (
background
иmask
), которые желательно бы использовать для иконок, потому что иконки — это дополнительная стилизация контента, а не сам контент.
Как видно из теста, символьный спрайт довольно ограничен в области применения — только и исключительно через use
. Остальные не сильно от него оторвались. А вариант css-спрайта вообще, что-то странное вытворяет. И только stack показывает идеальный результат — во всех четырёх способах использования видим ожидаемые иконки.
Почему же рассказывают про символьный? В виду его большей распространённости, которая случилась, потому что раньше нужно было поддерживать IE, который не умел в спрайты, но был полифил svg4everybody, который для IE генерировал png-иконки вместо svg. Этот полифил работал только с символьным спрайтом. И на самом деле, в те времена использование svg для иконок хотя бы через use
вместо иконочного шрифта — это уже было верхом профессионализма.
Но сейчас у нас нет этих ограничений. Теперь мы можем использовать удобный стековый спрайт, совсем избавив разметку от иконок.
Статью Simurai аж от 2 апреля 2012 года можно считать первоисточником (во всяком случае все упоминания стека в вебе, включая недавнюю статью Вадима Макеева, ссылаются на неё). В ней довольно сложно описывается устройство. Но можно значительно проще.
Устройство стека
Отдельные SVG иконки внутри общего (корневого) SVG просто складываются друг над другом — отсюда и название stack. При этом в отличие от символьного спрайта, тег svg
на symbol
не меняется. Но добавляется встроенный стиль, которым все иконки полностью скрываются, и показывается только нужная при обращении к ней по ссылке на фрагмент.
Допустим есть пара квадратных иконок с горизонтальной линией в одной и вертикальной в другой.
horizontal-line.svg:
<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"> <path d="m 0 12 h 24" stroke="black" /> </svg>
vertical-line.svg:
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> <path d="m 12 0 v 24" stroke="black" /> </svg>
Берём их код и просто складываем вместе в одном файле друг за другом (в любом порядке), при этом заносим имена файлов в id
соответствующих svg
. Оборачиваем их все в общий svg
, перенеся на него декларации неймспейсов (xmlns
). А внутрь, перед всеми иконками добавляем простой стиль.
<svg xmlns="http://www.w3.org/2000/svg"> <style> :root svg:not(:target) { display: none } </style> <svg id="horizontal-line" viewBox="0 0 20 20"> <path d="m 0 12 h 24" stroke="black" /> </svg> <svg id="vertical-line" viewBox="0 0 24 24"> <path d="m 12 0 v 24" stroke="black" /> </svg> </svg>
Теперь мы можем использовать эти иконки из стилей в фоне псевдоэлементов, если они статичные. А если нужно их динамически перекрашивать, то вместо background
мы можем использовать mask
(лучше сокращённое свойство, если будут использоваться кастомные свойства), который скроет часть псевдоэлемента, не попадающую в форму иконки (принцип трафарета, но наоборот), а оставшееся мы можем легко перекрашивать через изменение background
.
Если убрать тег<style>
, то при обращении к любому фрагменту будут видны вообще все иконки, которые попадут воviewBox
, указанный у запрашиваемого фрагмента (в случае данного примера будет виден плюсик, вместо одной из линий).
Автоматизация сборки стека
Для Gulp есть минимум три плагина для сборки спрайтов.
Огромный и тяжёлый монстр gulp-svg-sprite умеет собирать все пять видов спрайта. Но учитывая покрытие стеком всех юзкейсов, получается что бо́льшая часть функциональности этого плагина просто не нужна. К тому же он ещё и зачем-то в корневой svg
добавляет viewBox
с максимальными значениями из значений у иконок. Это не нужно, да ещё и мешает при стилизации — если этот viewBox
получился не квадратным, то настроить видимый размер иконки на странице становится сложно.
В большинстве случаев используется gulp-svgstore. Он небольшой и лёгкий. Но у него есть несколько проблем, важнейшая из которых — он собирает только символьный спрайт.
А вот gulp-stacksvg нам подходит — собирает удобный стек и избавлен от известных болячек двух других. Да ещё и заменяет атрибуты width
и height
у иконок на viewBox
с соответствующими размерами, если вдруг при оптимизации иконки забыли включить опцию предпочтения viewBox
.
Демонстрация рендеринга фрагментов стека, собранного этим плагином, во всех юзкейсах, включая перекраску через маски.
По умолчанию он собирает иконки в файл stack.svg
, но можно опцией output
передать ему нужное имя файла (как с расширением, так и без него), например sprite
, чтобы получить sprite.svg
.