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

якщо картинка була оголошена раніше.
 
 

Підсумок

З цим рішенням я працюю майже місяць і можу сказати, що воно економить дуже багато часу. Прагніть автоматизувати будь-яку рутину і використовувати свій час максимально ефективно.
 
Я для вас підготував репозиторій з робочим прикладом , який ви можете використовувати як основу для своїх проектів або просто подивитися його роботу.
 
 

Посилання

     
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.