В этом посте пойдёт речь о процессах и используемых инструментах для создания SVG спрайтов в студии Liquid Light.
Создание и поддержка больших SVG спрайтов может быть сложным делом и времязатратным. Поэтому мы решили автоматизировать процесс. И вместо использования одного большого SVG спрайта и отслеживания координат каждой иконки индивидуально, мы бы хотели иметь возможность редактировать каждую иконку и создавать и размещать сгенерированные иконки автоматически.
На практике это значит, что нам нужно сложить все наши SVG иконки в папку и будет создан SVG спрайт (и PNG резерв для IE8) и оптимизирован автоматически вместе с Sass картой или именами и скоординирован. Используя Sass миксины, мы далее сможем включать наши спрайты используя маленькие куски кода:
button {
&:before {
@include sprite(search);
}
}
Весь код можно найти на Github
[[$googleAdsence]]
Автоматизация процесса
Для интеграции SVG спрайтов в наш рабочий процесс, мы решили, что хотим чтобы исполнитель задач создавал спрайт - это значит, что мы могли бы отдельно создавать и обновлять индивидуальные иконки без редактирования и обновления целого изображения. Gulp - это выбранный нами исполнитель задач, который кроме всего прочего может запускать gulp-svg-sprites. Также мы хотели, чтобы CSS создавались автоматически - с размерами и позициями фона, вычисляемые при создании. Это даёт нам преимущество в возможности определять размеры иконок и обновлять CSS, чтобы они это отображали.
По-умолчанию, плагин gulp-svg-sprites генерирует свой собственный CSS, но typo3 имеет свои собственные классы, поэтому нам нужен способ создания размеров и положений как переменные и использовать их дальше в существующих селекторах. Для этого мы решили обратится к Sass.
При использовании Sass, иконки хранятся в массиве - или “карте” (подробнее про Sass карты). Используя некоторые миксины, мы можем вызывать любую иконку в спрайте и после компиляции, выводить размеры и позицию фона для каждой иконки.
Этот пост - это не вступление в Gulp или Sass (уже есть куча подобных вступлений в веб, можете почитать вот эту статью от Mark Goodyear, Sitepoint и Codefellows ), скорре этот пост описывает детально рабочий процесс для создания и использования SVG спрайтов. Он выполняется через плагины gulp, задачи gulp, которые мы установили и специфические миксины.
Плагины Gulp - package.json
Во-первых, нам нужны плагины для запуска задач по созданию спрайта. Наш файл package.json будет выглядеть вот так:
{
"devDependencies": {
"gulp": "^3.8.7",
"gulp-load-plugins": "^0.4.0",
"gulp-svg-sprites": "^1.0.0",
"gulp-svg2png": "^0.3.0",
"gulp-svgo": "^0.1.1",
"gulp-util": "^2.2.14"
}
}
Пробежимся по каждому из используемых плагинов
gulp-load-plugins- см. нижеgulp-svg-sprites- это тяжёлая артилерия, созадёт спрайты SVG и CSSgulp-svg2png- преобразовывает SVG в PNG - будем использовать для создания нашего PNG резерваgulp-svgo- SVG оптимизатор - для оптимизации наших SVG иконок перед тем, как мы создадим спрайтgulp-util- используется для вывода цветных сообщений на экран
Плагин gulp-load-plugins (от Jack Franklin), который находится в package.json и загружает все плагины gulp как один большой проект - это значит, что вам не нужно указывать каждый из них в вашем gulp файле. Сэкономит чуть вам времени!
`var gulp = require(‘gulp’);
var gutil = require(‘gulp-util’); var plugins = require(“gulp-load-plugins”)({ pattern: [‘gulp-’, ‘gulp.’], replaceString: /\bgulp[-.]/ });`
После определения плагинов для их использования вам нужно вызывать нужный плагин в объекте.
.pipe(plugins.svg2png())
Gulp задача - gulpfile.js
У нас есть несколько gulp задач, чтобы сделать спрайт и соответствующие файлы (см. ниже). Первая задача svgSprite будет наблюдать за некоторой папкой; при добавлении или редактировании SVG файлов будет запускаться задача и будут созданы спрайт (с соответствующим scss файлом).
Отдельные SVG файлы проходят через оптимизатор SVG преед помещением в спрайт, чтобы обеспечить наименее возможный размер.
Далее, задача pngSprite конвертирует SVG в PNG спрайт для IE8 и ниже.
Мы храним все наши пути и плагины в объектах в начале файла, но они могут быть просто заменены в нужных местах ниже (полный файл для загрузки можно найти в Github репо).
Внимание Mac safari выдаёт разные результаты (при использовании em для положений фона), в отличие от других браузеров когда спрайт создан в вертикальном или горизонтальном виде. Диагональ - это единственный макет, когда все браузеры ведут себя одинаково.
Внимание Убедитесь, что ваш спрайт не превышает размеры 2300px x 2300px - иначе <= iOS7 вообще не покажет изображение.
` gulp.task(‘svgSprite’, function () {
return gulp.src(paths.sprite.src)
.pipe(plugins.svgo())
.pipe(plugins.svgSprites({
cssFile: paths.sprite.css,
preview: false,
layout: 'diagonal',
padding: 5,
svg: {
sprite: paths.sprite.svg
},
templates: {
css: require("fs").readFileSync(paths.templates.src + 'sprite-template.scss', "utf-8")
}
}))
.pipe(gulp.dest(basePaths.dest));
});
gulp.task(‘pngSprite’, [‘svgSprite’], function() { return gulp.src(basePaths.dest + paths.sprite.svg) .pipe(plugins.svg2png()) .pipe(gulp.dest(paths.images.dest)); });
gulp.task(‘sprite’, [‘pngSprite’]);`
Scss шаблон - sprite-template.scss
Чтобы убедится, что данные выходят из задания svgSprites так, как нам нужно, мы передаётм в шаблон используя плейсхолденры для генерированния данных. Наша карта спрайтов содержит данные о спрайте как о целом, плюс отдельные иконки, находящиеся всередине спрайта сами по себе.
Наш sprite-template.scss выглядит вот так (добавил пару строк для читаемости):
{#common}
$icons: (
sprite: (width: {swidth}px, height: {sheight}px, pngPath: '{pngPath}', svgPath: '{svgPath}'),
{/common}
{#svg}
{name}: (width: {width}px, height: {height}px, backgroundX: {positionX}px, backgroundY: {positionY}px),
{/svg}
{#common}
);
{/common}
Блоки {common} сообщают генератору шаблонов, выводить эти блоки только раз. Первый объект открывает карту и вставляет данные о спрайте (ширину, высоту, путь к PNG и путь к SVG). Блок {common} в конце просто закрывает карту Sass.
Блок {svg} в середине проходит циклом через каждый файл и назначает имя файла, разрешение и положение фона.
Используя этот шаблон вместе с плагином gulp-svg-sprite, получим следующее:
`$icons: ( sprite: (width: 104px, height: 96px, pngPath: ‘../img/sprite.png’, svgPath: ‘../img/sprite.svg’),
facebook: (width: 10px, height: 22px, backgroundX: 0px, backgroundY: 0px),
twitter: (width: 32px, height: 22px, backgroundX: -20px, backgroundY: -32px),
twitterHover: (width: 32px, height: 22px, backgroundX: -62px, backgroundY: -64px),
);`
Все положения и размеры обновляются динамически, мы можем просто добавить новую иконку к нашей папке или предложить альтернативу существующей и будет перезапущена задача gulp и внесены изменения.
Scss миксины и функции
С сгенерированной картой, мы могли бы начать использовать значения нашего Scss файла следующим образом:
` @import “src/sprite”;
.class { $twitter: map-get($icons, twitter); $sprite: map-get($icons, sprite); width: map-get($twitter, width); height: map-get($twitter, height); background-image: url(map-get($sprite, svgPath)); background-position: map-get($twitter, backgroundX) map-get($twitter, backgroundX); }`
Вы поняли идею - это всё очень долго и нужно делать для каждой иконки, которую мы хотим использовать. Код выше не должен включать конвертирование px в em!
Чтобы избежать проблем, мы создали банк миксинов Scss, чтобы упростить использование спрайтов:
`@import ‘src/sprite’;
$ieSprite: ‘.lt-ie9’ !default; $sprite: map-get($icons, sprite) !default; $baseFontSize: 16px !default;
@import ‘mixins’;
.class { @include sprite(phone); }`
И вместо одного универсального миксина, мы разбили его на несколько простых миксинов, плейсхолдеров и функций - что значит, что мы можем вызывать отдельные атрибуты (например: нет смысла переназначать фоновое изображение или размеры иконки, если иконка изменяется при наведении на неё (:hover)).
Так как наши сайты поддерживают IE8, поэтому PNG и px резервы очень важны.
Переменные
Нужно установить парочку переменных, чтобы потом было легче поддерживать:
$ieSprite: '.lt-ie9' !default;
$sprite: map-get($icons, sprite) !default;
$baseFontSize: 16px !default;
$ieSprite- объявляет класс необходимый для ie спрайта. При отсутствии не будет сгенерирован IE PNG резерв.$sprite- устанавливает переменную для основных данных спрайта (путь файла, размеры и др.)$baseFontSize- используется для вычислений mq-px2em
Функции
Далее, извлекаются функции и возвращают указанный атрибут для указанной иконки из sass карты. Мы также включили библиотеку от Guardian sass-mq library, что значит у нас есть функция mq-px2em.
`// Получение атрибутов из sass карты @function sprite-attr($icon, $attr) { $icon: map-get($icons, $icon); @return map-get($icon, $attr); }
@function icon-attr($icon) { $attr: ( width: sprite-attr($icon, width), height: sprite-attr($icon, height), x: sprite-attr($icon, backgroundX), y: sprite-attr($icon, backgroundY) );
@return $attr;
}`
Плейсхолдеры
Плейсхолдеры устанавливают фон как спрайт SVG или PNG спрайт, если класс для body содержит .lt-ie9
// Установка фона и размера с IE резервом
%sprite {
display: inline-block;
background-image: url(map-get($sprite, svgPath));
background-size: mq-px2em(map-get($sprite, width)) mq-px2em(map-get($sprite, height));
}
%ie-sprite {
background-image: url(map-get($sprite, pngPath));
}
Миксины
Наконец у нас есть спрайт миксины. Есть миксин ie-sprite(), у которого схожый функционал, но он использует px вместо em и добавляет к селектору класс .lt-ie9.
`// Для использования с gulp спрайт плагином @mixin sprite($icon, $type: all) { @if $type == all { // Shares the backgrounds @extend %sprite; }
$iconMap: icon-attr($icon);
// Вывод размеров в em
@if $type == all or $type == size {
width: mq-px2em(map-get($iconMap, width) + 1);
height: mq-px2em(map-get($iconMap, height) + 1);
}
// Вывод положения фона в em
@if $type == all or $type == bg {
background-position: mq-px2em(map-get($iconMap, x)) mq-px2em(map-get($iconMap, y));
}
// Добавление ie резерва
@include ie-sprite($icon, $type);
}`
Эти спрайт миксины берут 2 параметры - первый - это имя нужной иконки, второй - опциональный и позволяет пользователю определить размер size или фон bg для получения соответствующих атрибутов.
Использование
С установленным gulp процессом и при использовании миксинов, получить иконку для вывода очень просто:
`class { &:before { @include sprite(twitter); content: ‘’; float: left; margin-right: 0.5em; }
&:hover {
&:before {
@include sprite(twitterHover, bg);
}
}
}`
Вывод CSS:
`.class:before { display: inline-block; background-image: url("../img/sprite.svg"); background-size: 6.5em 6em; }
.lt-ie9 .class:before { background-image: url("../img/sprite.png"); }
.class:before { width: 2.0625em; height: 1.4375em; background-position: -1.25em -2em; content: ‘’; float: left; margin-right: 0.5em; } .lt-ie9 .class:before { width: 32px; height: 22px; background-position: -20px -32px; } .class:hover:before { background-position: -3.875em -4em; } .lt-ie9 .class:hover:before { background-position: -62px -64px; }`
Хотя кажется, что много кода, на самом деле не более, чем бы у вас заняло написание всего CSS вручную. SVG устанавливается как фон для любой иконки использующей спрайт (только если у них нет lt-ie9 класса для body, в этом случае они получают PNG). С этого момента, положение фона, ширина и высота устанавливаются для каждого селектора отдельно - с px резервом для IE8 и ниже.
Весь приведенный код может быть найден на Github.
Если у вас есть какие-то замечания или предложения по улучшению кода, то комментируйте ниже или делайте это на гитхабе через пулл-реквест!
Источник - статья Creating SVG Sprites using Gulp and Sass