Генерация CSS-спрайтов с Gulp
Работая над одним большим проектом, мы с напарником задумались над тем, чтобы автоматизировать процесс сбора спрайтов на проекте.До этого спрайты собирались ручками или с помощью онлайн сервисов, что отнимало достаточно времени.Проект уже собирался 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 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 движком) algorithmOpts — опции алгоритмаsort — включение/выключение сортировки изображений. По умолчанию стоит true engineOpts — опции движкаimagemagick — true/false, приоритетное использование imagemagick вместо graphicsmagick (есть только в gm) 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 ``` */ .icon-home { background-image: url (sprite.png); background-position: 0 px 0 px; width: 16 px; height: 16 px; } .icon-home_hover { background-image: url (sprite.png); background-position: 0 px -16 px; width: 16 px; height: 16 px; } .icon-instagram { background-image: url (sprite.png); background-position: 0 px -32 px; width: 16 px; height: 16 px; } .icon-instagram_hover { background-image: url (sprite.png); background-position: 0 px -48 px; width: 16 px; height: 16 px; } .icon-pin { background-image: url (sprite.png); background-position: 0 px -64 px; width: 12 px; height: 16 px; } .icon-pin_hover { background-image: url (sprite.png); background-position: 0 px -80 px; width: 12 px; height: 16 px; } .icon-tras_hover { background-image: url (sprite.png); background-position: 0 px -96 px; width: 16 px; height: 16 px; } .icon-trash { background-image: url (sprite.png); background-position: 0 px -112 px; width: 16 px; height: 16 px; } .icon-user { background-image: url (sprite.png); background-position: 0 px -128 px; width: 16 px; height: 16 px; } .icon-user_hover { background-image: url (sprite.png); background-position: 0 px -144 px; width: 16 px; height: 16 px; }
Тонкая настройка У нас в проекте используется 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 = 16 px 0 px -16 px 0 px 16 px 16 px 80 px 64 px 'sprite.png'; $s-book_hover = 48 px 16 px -48 px -16 px 16 px 16 px 80 px 64 px 'sprite.png'; $s-comments = 0 px 16 px 0 px -16 px 16 px 16 px 80 px 64 px 'sprite.png'; $s-comments_hover = 16 px 16 px -16 px -16 px 16 px 16 px 80 px 64 px 'sprite.png'; $s-compose = 32 px 0 px -32 px 0 px 16 px 16 px 80 px 64 px 'sprite.png'; $s-compose_hover = 32 px 16 px -32 px -16 px 16 px 16 px 80 px 64 px 'sprite.png'; $s-faceboo_hover = 0 px 32 px 0 px -32 px 16 px 16 px 80 px 64 px 'sprite.png'; $s-facebook = 16 px 32 px -16 px -32 px 16 px 16 px 80 px 64 px 'sprite.png'; $s-globe = 32 px 32 px -32 px -32 px 16 px 16 px 80 px 64 px 'sprite.png'; $s-globe_hover = 48 px 0 px -48 px 0 px 16 px 16 px 80 px 64 px 'sprite.png'; $s-home = 0 px 0 px 0 px 0 px 16 px 16 px 80 px 64 px 'sprite.png'; $s-home_hover = 48 px 32 px -48 px -32 px 16 px 16 px 80 px 64 px 'sprite.png'; $s-instagram = 0 px 48 px 0 px -48 px 16 px 16 px 80 px 64 px 'sprite.png'; $s-instagram_hover = 16 px 48 px -16 px -48 px 16 px 16 px 80 px 64 px 'sprite.png'; $s-pin = 32 px 48 px -32 px -48 px 12 px 16 px 80 px 64 px 'sprite.png'; $s-pin_hover = 44 px 48 px -44 px -48 px 12 px 16 px 80 px 64 px 'sprite.png'; $s-tras_hover = 64 px 0 px -64 px 0 px 16 px 16 px 80 px 64 px 'sprite.png'; $s-trash = 64 px 16 px -64 px -16 px 16 px 16 px 80 px 64 px 'sprite.png'; $s-user = 64 px 32 px -64 px -32 px 16 px 16 px 80 px 64 px 'sprite.png'; $s-user_hover = 64 px 48 px -64 px -48 px 16 px 16 px 80 px 64 px '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:16 px; height:16 px Миксин позволяет нам сразу выводить ширину и высоту картинки — это очень удобно, особенно при использовании псевдоэлементов для оформления.Рабочий примерПроблемы За все время использования этого решения я встретил только одну проблему.При : hover и : active иконка будет мигать. Происходит это потому, что миксин sprite каждый раз генерирует background-image и при ховере браузер подставляет эту картинку.Немного подумав и почитав документацию stylus, было найдено решение.Нам просто нужно проверять наличие вышеперечисленных псевдоклассов у селектора. Если они есть, то мы пропускаем вывод spriteImage ($sprite).Финальный mixin
sprite ($sprite) if! match ('hover', selector ()) && ! match ('active', selector ()) spriteImage ($sprite) spritePosition ($sprite) spriteWidth ($sprite) spriteHeight ($sprite) К сожалению, все варианты предусмотреть не получится — иногда это может быть изменение класса через js, поэтому мы можем просто использовать
spritePosition ($sprite) если картинка была объявлена ранее.Итог С этим решением я работаю почти месяц и могу сказать, что оно экономит очень много времени. Стремитесь автоматизировать любую рутину и использовать свое время максимально эффективно.Я для вас подготовил репозиторий с рабочим примером, который вы можете использовать как основу для своих проектов или просто посмотреть его работу.
Ссылки