...

понедельник, 7 июля 2014 г.

Генерация 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
<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).

Финальный mixin



sprite($sprite)
if !match('hover', selector()) && !match('active', selector())
spriteImage($sprite)
spritePosition($sprite)
spriteWidth($sprite)
spriteHeight($sprite)


К сожалению, все варианты предусмотреть не получится — иногда это может быть изменение класса через js, поэтому мы можем просто использовать



spritePosition($sprite)




если картинка была объявлена ранее.

Итог




С этим решением я работаю почти месяц и могу сказать, что оно экономит очень много времени. Стремитесь автоматизировать любую рутину и использовать свое время максимально эффективно.

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


Ссылки




This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


Комментариев нет:

Отправить комментарий