
Работая над одним большим проектом, мы с напарником задумались над тем, чтобы автоматизировать процесс сбора спрайтов на проекте.
До этого спрайты собирались ручками или с помощью онлайн сервисов, что отнимало достаточно времени.
Проект уже собирался Gulp'ом и было принято решение найти адаптированный под него сборщик спрайтов.
Вариантов было несколько:
Первый вариант сложен в установке, есть несколько зависимостей, для которых приходилось ставить дополнительные пакетные менеджеры. Если в проект добавится новый разработчик — придется обьяснять ему что к чему. А это не тот путь, который мы выбрали. Также, не было гибкой настройки расположения картинок в спрайте.
Остальные 3 варианта — это реализации на одном движке spritesmith. В итоге выбор пал на официальный порт для Gulp.
Установка
Самое первое, что надо сделать — установить Gulp на компьютер. Официальная документация поможет вам справиться с этим шагом.
Затем ставим gulp.spritesmith. В моем случае проект чистый, поэтому я ставлю все необходимые зависимости.
npm i gulp gulp-stylus gulp.spritesmith --save
Теперь можно переходить к настройке генератора.
Настройка
Перед тем как приступить непосредственно к описанию таска, ознакомимся с параметрами, которые принимает функция.
- imgName — имя генерируемой картинки
- поддерживаются расширения
.pngи.jpg/.jpeg(зависит от используемого движка) - формат картинки, может быть переписан свойством
imgOpts.format
- поддерживаются расширения
- cssName — имя css файла, который получится на выходе
- поддерживаемые CSS расширения
.css(CSS),.sass(SASS),.scss(SCSS),.less(LESS),.styl/.stylus(Stylus) и.json(JSON) - расширение может быть переписано свойством
cssFormat
- поддерживаемые CSS расширения
- imgPath — путь к спрайту, будет записываться в CSS
- engine — движок, используемый для генерации спрайта
- по умолчанию стоит
autoи будет использован наиболее подходящий движок на вашей системе - поддерживаемые значения
phantomjs,canvas,gm,pngsmith
- по умолчанию стоит
- algorithm — способ сортировки изображений
- поддерживаемые значения
top-down(по умолчанию),left-right,diagonal,alt-diagonal,binary-tree
- поддерживаемые значения
- padding — отступ между картинками. По умолчанию отступа нет
- imgOpts — настройки спрайта
- format — формат картинки
- поддерживаются форматы
pngиjpg(зависит от используемого движка)
- поддерживаются форматы
- quality — качество, поддерживается только
gmдвижком - timeout — задержка до завершения рендеринга в миллисекундах (поддерживается только
phantomjsдвижком)
- format — формат картинки
- algorithmOpts — опции алгоритма
- sort — включение/выключение сортировки изображений. По умолчанию стоит
true
- sort — включение/выключение сортировки изображений. По умолчанию стоит
- engineOpts — опции движка
- imagemagick — true/false, приоритетное использование
imagemagickвместоgraphicsmagick(есть только вgm)
- imagemagick — true/false, приоритетное использование
- cssFormat — выбор формата CSS файла
- поддерживаемые значения
css(CSS),sass(SASS),scss(SCSS),scss_maps(SCSS используя map notation),less(LESS),stylus(Stylus) иjson(JSON)
- поддерживаемые значения
- cssVarMap — цикл, позволяющий настраивать названия CSS переменных
- cssTemplate — функция или путь до
mustacheшаблона, дающие возможность настроить CSS-файл на выходе - cssOpts — опции CSS-шаблонов
- functions — пропустить генерацию миксинов
- cssClass — цикл, переписывающий стандартные CSS-селекторы
Исходя из этого, самый простой таск будет иметь следующий вид:
gulp.task('sprite', function() { var spriteData = gulp.src('./src/assets/images/sprite/*.*') // путь, откуда берем картинки для спрайта .pipe(spritesmith({ imgName: 'sprite.png', cssName: 'sprite.css', })); spriteData.img.pipe(gulp.dest('./built/images/')); // путь, куда сохраняем картинку spriteData.css.pipe(gulp.dest('./built/styles/')); // путь, куда сохраняем стили });
У нас получился такой спрайт:

И следующий CSS-код:
Скрытый текст
/* Icon classes can be used entirely standalone. They are named after their original file names. ```html <i class="icon-home"></i> ``` */ .icon-home { background-image: url(sprite.png); background-position: 0px 0px; width: 16px; height: 16px; } .icon-home_hover { background-image: url(sprite.png); background-position: 0px -16px; width: 16px; height: 16px; } .icon-instagram { background-image: url(sprite.png); background-position: 0px -32px; width: 16px; height: 16px; } .icon-instagram_hover { background-image: url(sprite.png); background-position: 0px -48px; width: 16px; height: 16px; } .icon-pin { background-image: url(sprite.png); background-position: 0px -64px; width: 12px; height: 16px; } .icon-pin_hover { background-image: url(sprite.png); background-position: 0px -80px; width: 12px; height: 16px; } .icon-tras_hover { background-image: url(sprite.png); background-position: 0px -96px; width: 16px; height: 16px; } .icon-trash { background-image: url(sprite.png); background-position: 0px -112px; width: 16px; height: 16px; } .icon-user { background-image: url(sprite.png); background-position: 0px -128px; width: 16px; height: 16px; } .icon-user_hover { background-image: url(sprite.png); background-position: 0px -144px; width: 16px; height: 16px; }
Тонкая настройка
У нас в проекте используется CSS-препроцессор Stylus, поэтому мне удобнее будет сохранять это как .styl фай�� с переменными.
Для компактности я включил алгоритм распределения картинок
binary-tree. Всем переменным, для наглядности, я даю префикс s-. Отключаю генерацию миксинов и выношу их в отдельный файл. И создаю свой CSS-шаблон, потому, что по умолчанию генерируется много лишнего мусора, который порядочно раздувает файл и мной не используется.В итоге, спрайт будет иметь следующий вид:

js + stylus код
gulp.task('sprite', function() { var spriteData = gulp.src('./src/assets/images/sprite/*.*') // путь, откуда берем картинки для спрайта .pipe(spritesmith({ imgName: 'sprite.png', cssName: 'sprite.styl', cssFormat: 'stylus', algorithm: 'binary-tree', cssTemplate: 'stylus.template.mustache', cssVarMap: function(sprite) { sprite.name = 's-' + sprite.name } })); spriteData.img.pipe(gulp.dest('./built/images/')); // путь, куда сохраняем картинку spriteData.css.pipe(gulp.dest('./src/styles/')); // путь, куда сохраняем стили });
$s-book = 16px 0px -16px 0px 16px 16px 80px 64px 'sprite.png'; $s-book_hover = 48px 16px -48px -16px 16px 16px 80px 64px 'sprite.png'; $s-comments = 0px 16px 0px -16px 16px 16px 80px 64px 'sprite.png'; $s-comments_hover = 16px 16px -16px -16px 16px 16px 80px 64px 'sprite.png'; $s-compose = 32px 0px -32px 0px 16px 16px 80px 64px 'sprite.png'; $s-compose_hover = 32px 16px -32px -16px 16px 16px 80px 64px 'sprite.png'; $s-faceboo_hover = 0px 32px 0px -32px 16px 16px 80px 64px 'sprite.png'; $s-facebook = 16px 32px -16px -32px 16px 16px 80px 64px 'sprite.png'; $s-globe = 32px 32px -32px -32px 16px 16px 80px 64px 'sprite.png'; $s-globe_hover = 48px 0px -48px 0px 16px 16px 80px 64px 'sprite.png'; $s-home = 0px 0px 0px 0px 16px 16px 80px 64px 'sprite.png'; $s-home_hover = 48px 32px -48px -32px 16px 16px 80px 64px 'sprite.png'; $s-instagram = 0px 48px 0px -48px 16px 16px 80px 64px 'sprite.png'; $s-instagram_hover = 16px 48px -16px -48px 16px 16px 80px 64px 'sprite.png'; $s-pin = 32px 48px -32px -48px 12px 16px 80px 64px 'sprite.png'; $s-pin_hover = 44px 48px -44px -48px 12px 16px 80px 64px 'sprite.png'; $s-tras_hover = 64px 0px -64px 0px 16px 16px 80px 64px 'sprite.png'; $s-trash = 64px 16px -64px -16px 16px 16px 80px 64px 'sprite.png'; $s-user = 64px 32px -64px -32px 16px 16px 80px 64px 'sprite.png'; $s-user_hover = 64px 48px -64px -48px 16px 16px 80px 64px 'sprite.png';
Использование
Спрайт сгенерирован, stylus файл с переменными есть — что дальше?
Дальше нам помогут со всем этим работать миксины, которые генерирует по умолчанию плагин и которые мы отключили.
Для них я создал отдельный файл
mixins.styl.Содержимое файла
mixins.styl:spriteWidth($sprite) { width: $sprite[4]; } spriteHeight($sprite) { height: $sprite[5]; } spritePosition($sprite) { background-position: $sprite[2] $sprite[3]; } spriteImage($sprite) { background-image: url(../images/$sprite[8]); } sprite($sprite) { spriteImage($sprite) spritePosition($sprite) spriteWidth($sprite) spriteHeight($sprite) }
Основной миксин для нас это
sprite($sprite). Вместо $sprite вставляем нужную нам переменную. Например, sprite($s-home).Результат получится такого вида:
background-image:url("../images/sprite.png"); background-position:0 0; width:16px; height:16px
Миксин позволяет нам сразу выводить ширину и высоту картинки — это очень удобно, особенно при использовании псевдоэлементов для оформления.
Рабочий пример
Проблемы
За все время использования этого решения я встретил только одну проблему.
При
:hover и :active иконка будет мигать. Происходит это потому, что миксин sprite каждый раз генерирует background-image и при ховере браузер подставляет эту картинку.Немного подумав и почитав документацию
stylus, было найдено решение.Нам просто нужно проверять наличие вышеперечисленных псевдоклассов у селектора. Если они есть, то мы пропускаем вывод
spriteImage($sprite).Финальный
mixinsprite($sprite) if !match('hover', selector()) && !match('active', selector()) spriteImage($sprite) spritePosition($sprite) spriteWidth($sprite) spriteHeight($sprite)
К сожалению, все варианты предусмотреть не получится — иногда это может быть изменение класса через js, поэтому мы можем просто использовать
spritePosition($sprite)
если картинка была объявлена ранее.
Итог
С этим решением я работаю почти месяц и могу сказать, что оно экономит очень много времени. Стремитесь автоматизировать любую рутину и использовать свое время максимально эффективно.
Я для вас подготовил репозиторий с рабочим примером, который вы можете использовать как основу для своих проектов или просто посмотреть его работу.
