CSS sprite generation with gulp

  • Tutorial

While working on one large project, my partner and I thought about how to automate the process of collecting sprites on the project.
Prior to this, sprites were collected using pens or using online services, which took a lot of time.
The project was already being assembled by Gulp, and it was decided to find a sprite collector adapted for it.

There were several options:

The first option is difficult to install, there are several dependencies for which you had to install additional package managers. If a new developer is added to the project, he will have to explain to him what's what. And this is not the path that we have chosen. Also, there was no flexible adjustment of the location of the pictures in the sprite.

The remaining 3 options are implementations on the same spritesmith engine . As a result, the choice fell on the official port for Gulp.

Installation


The very first thing to do is install Gulp on your computer. The official documentation will help you deal with this step.
Then put gulp.spritesmith. In my case, the project is clean, so I put all the necessary dependencies.

npm i gulp gulp-stylus gulp.spritesmith --save


Now you can proceed to setting up the generator.

Customization


Before proceeding directly to the description of the task, we will familiarize ourselves with the parameters that the function accepts.

  • imgName - name of the generated image
    • extensions are supported .pngand .jpg/.jpeg(depending on the engine used)
    • picture format, can be overwritten by property imgOpts.format
  • cssName - the name of the css file that will be output
    • supported CSS extensions .css(CSS), .sass(SASS), .scss(SCSS), .less(LESS), .styl/.stylus(Stylus) and .json(JSON)
    • extension can be rewritten by property cssFormat
  • imgPath - path to the sprite, will be written in CSS
  • engine - the engine used to generate the sprite
    • the default is autoand will use the most suitable engine on your system
    • supported values phantomjs, canvas, gm, pngsmith
  • algorithm - image sorting method
    • supported values top-down(default), left-right, diagonal, alt-diagonal,binary-tree
  • padding - indent between images. There is no indentation by default
  • imgOpts - sprite settings
    • format - picture format
      • formats are supported pngand jpg(depending on the engine used)
    • quality - quality, supported only by the gmengine
    • timeout - delay until the completion of rendering in milliseconds (supported only by the phantomjsengine)
  • algorithmOpts - algorithm options
    • sort - enable / disable image sorting. Defaults totrue
  • engineOpts - engine options
    • imagemagick - true / false, priority use imagemagickinstead graphicsmagick(only available gm)
  • cssFormat - select CSS file format
    • Supported Values css(CSS), sass(SASS), scss(SCSS), scss_maps(SCSS using map notation), less(LESS), stylus(Stylus) and json(JSON)
  • cssVarMap - a loop that allows you to customize the names of CSS variables
  • cssTemplate - a function or a path to the mustachetemplate that allows you to customize the CSS file at the output
  • cssOpts - CSS template options
    • functions - skip mixin generation
    • cssClass - a loop rewriting standard CSS selectors


Based on this, the simplest task will have the following form:
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/')); // путь, куда сохраняем стили
});


We got the following sprite:


And the following CSS:
Hidden text
/*
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: 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;
}



Fine tuning

We have used the Stylus CSS preprocessor in our project, so it will be more convenient for me to save this as a .styl file with variables.
For compactness, I have included an image distribution algorithm binary-tree. All variables, for clarity, I give a prefix s-. I turn off the generation of mixins and put them out in a separate file. And I create my own CSS template, because by default a lot of extra garbage is generated, which decently inflates the file and is not used by me.

As a result, the sprite will have the following form:


js + stylus code
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';



Using


The sprite is generated, there is a stylus file with variables - what's next?
Next, the mixins that the plugin generates by default and which we turned off will help us with all this.
I created a separate file for them mixins.styl.

File contents 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)
}


The main mixin for us is this sprite($sprite). Instead, we $spriteinsert the variable we need. Eg sprite($s-home).
The result will look like this:
background-image:url("../images/sprite.png");
background-position:0 0;
width:16px;
height:16px

The mixin allows us to immediately display the width and height of the image - this is very convenient, especially when using pseudo-elements for decoration.
Working example

Problems


For all the time using this solution, I met only one problem.
When :hoverand the :activeicon will blink. This happens because the mixin spritegenerates every time background-imageand when the browser hovers, it substitutes this image.
After thinking a little and reading the documentation stylus, a solution was found.
We just need to check for the presence of the above pseudo-classes on the selector. If they are, then we skip the conclusion spriteImage($sprite).

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


Unfortunately, it’s impossible to foresee all the options - sometimes it can be a class change through js, so we can just use
spritePosition($sprite)

if the picture was announced earlier.

Total


I have been working with this solution for almost a month and I can say that it saves a lot of time. Strive to automate any routine and use your time as efficiently as possible.

I have prepared a repository for you with a working example , which you can use as a basis for your projects or just see its work.

References



Also popular now: