【深圳】DJI 大疆创新 互联网团队 前端及大量职位招聘中 (内推 15-50k + 丰厚年终 + 股份)简历请发至 evan.zhou@dji.com, 合适的话当天回复,当天内推。 更多福利

CSS Sprites指的是网页图片的一种处理技巧,普遍使用于各大类型的网站上面,基本上随便打开一个网页,查看资源,你都会看到类似的图片。

http://static.w3ctrain.com/generating-sprites-with-gulp-example2.png

通常是一些体积很小,不常更换的图片,目的很简单,减少HTTP请求次数。

也常用来制作按钮切换状态。
http://static.w3ctrain.com/generating-sprites-with-gulp-example.png

古老的做法

在学gulp之前,我通常会找在线工具来帮我拼图,比如之前提到的spritegen。我只要上传图片,设置一下就能完成,下载下来,在样式表中计算sprite的大小位置。
但是需求是不断变动的(开发阶段图片会经常调整,比如发现图片出现了1px的白边@我们伟大的iOS攻城狮兼UI射鸡湿Pandara_Wen),那么就得重复操作,上传下载替换,上传下载替换,上传下载替换,上传下载替换…当很多次重复操作之后,相信我,你肯定会疯掉的。

回到主题,使用gulp生成sprites图片和css。

我的想法是在本地把精灵图片放到某个文件夹,然后通过gulp及其插件,将精灵图标拼接,并最终生成一张大图和相应的样式表,再把样式表复制到它该去的地方,就行了,不需要再去计算每个元素的大小,位置。(这里需要计算的主要原因是精灵图的位置会有变化,而且我们直接使用2倍图)

相关插件

google了一下 gulp sprite出来的几个:

css-sprite稍稍有点麻烦,gulp-sprite很久没人更新了,下载量也很小(果断跳过这个坑),gulp-sprite-generator尝试了很久,最后才发现Demo中gulp.src(‘./src/css/*.css’)选中的是css文件,它是用来给已经写好了的样式表替换路径和生成相应的样式表以及图片的。

最后我选择了gulp.spritesmith。

gulp.spritesmith

http://static.w3ctrain.com/generating-sprites-with-gulp-gulp.spritesmith.png
spritesmith的作用就是拼接图片并生成样式表,并且还能输出SASS,Stylus,LESS甚至是JSON。

安装

1
npm install gulp gulp-sass gulp-imagemin gulp.spritesmith --save

官方Demo。

1
2
3
4
5
6
7
8
9
10
var gulp = require('gulp');
var spritesmith = require('gulp.spritesmith');

gulp.task('sprite', function () {
var spriteData = gulp.src('images/*.png').pipe(spritesmith({
imgName: 'sprite.png',
cssName: 'sprite.css'
}));
return spriteData.pipe(gulp.dest('path/to/output/'));
});

运行最终生成的是sprite.png,和sprite.css
http://static.w3ctrain.com/generating-sprites-with-gulp-sprite.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

.icon-icon_baby {
background-image: url(sprite.png);
background-position: -70px 0px;
width: 41px;
height: 55px;
}
.icon-scale_icon {
background-image: url(sprite.png);
background-position: 0px -50px;
width: 50px;
height: 53px;
}
.icon-weight_icon {
background-image: url(sprite.png);
background-position: 0px 0px;
width: 70px;
height: 50px;
}

跟使用在线工具效果一样了!

大概看了下文档,切换sass格式输出结果:

1
2
3
4
5
6
7
8
9
10
11
var gulp = require('gulp');
var spritesmith = require('gulp.spritesmith');

gulp.task('sprite', function () {
var spriteData = gulp.src('images/*.png').pipe(spritesmith({
imgName: 'sprite.png',
cssName: 'sprite.scss',
cssFormat: 'scss'
}));
return spriteData.pipe(gulp.dest('path/to/output/'));
});

sprite.scss文件生成了很多内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
$icon-baby-name: 'icon_baby';
$icon-baby-x: 70px;
$icon-baby-y: 0px;
$icon-baby-offset-x: -70px;
$icon-baby-offset-y: 0px;
$icon-baby-width: 41px;
$icon-baby-height: 55px;
$icon-baby-total-width: 111px;
$icon-baby-total-height: 103px;
$icon-baby-image: 'sprite.png';
$icon-baby: (70px, 0px, -70px, 0px, 41px, 55px, 111px, 103px, 'sprite.png', 'icon_baby', );

//另外两个icon也同样输出一大串

@mixin sprite-width($sprite) {
width: nth($sprite, 5);
}

@mixin sprite-height($sprite) {
height: nth($sprite, 6);
}

@mixin sprite-position($sprite) {
$sprite-offset-x: nth($sprite, 3);
$sprite-offset-y: nth($sprite, 4);
background-position: $sprite-offset-x $sprite-offset-y;
}

@mixin sprite-image($sprite) {
$sprite-image: nth($sprite, 9);
background-image: url(#{$sprite-image});
}

@mixin sprite($sprite) {
@include sprite-image($sprite);
@include sprite-position($sprite);
@include sprite-width($sprite);
@include sprite-height($sprite);
}

/*
The `sprites` mixin generates identical output to the CSS template
but can be overridden inside of SCSS

@include sprites($spritesheet-sprites);
*/
@mixin sprites($sprites) {
@each $sprite in $sprites {
$sprite-name: nth($sprite, 10);
.#{$sprite-name} {
@include sprite($sprite);
}
}
}

输出内容稍微有点繁琐,最终使用的时候非常简单,我只需要在元素中include 一下就行了(不需要每次都去查找元素,修改!!!)

1
2
3
.baby {
@include sprite($icon-baby);
}

为了让代码更加优雅,我使用了使用cssTemplate参数来自定义模板:

1
2
3
4
5
imgName: 'sprite.png',
cssName: 'sprite.scss',
cssFormat: 'scss',
cssTemplate: 'scss.template.mustache',
cssOpts: 'spriteSrc',

scss.template.mustache文件是这样的。

1
2
3
4
${{options}}:'{{spritesheet.escaped_image}}';
{{#items}}
${{name}} : {{px.x}} {{px.y}} {{px.offset_x}} {{px.offset_y}} {{px.width}} {{px.height}} {{px.total_width}} {{px.total_height}} ${{../options}} ;
{{/items}}

模板用的mustache
{ {} }是输出,#符号是循环,../的意思是返回上一层的作用域链(很奇葩,今天坑了很久!)

options的值是配置中的cssOpts传过来的,支持对象。我用它来声明sprite路径的变量,这样每次只需要修改这个变量就行了。来看看最终的生成效果:

1
2
3
4
5
6
$spriteSrc:'sprite.png';
//懂我只修改这个变量的意思吗?

$icon_baby : 70px 0px -70px 0px 41px 55px 111px 103px $spriteSrc ;
$scale_icon : 0px 50px 0px -50px 50px 53px 111px 103px $spriteSrc ;
$weight_icon : 0px 0px 0px 0px 70px 50px 111px 103px $spriteSrc ;

由于图片最终要上传到cdn,所以sprite.png输不输出没有关系。

总算是顺眼了很多。我们再把那些mixin放到文件的顶部即可,每次增删改只需要生成生成图片,替换整个sprite.scss文件即可!

Retina

gulp.spritesmith还支持拼接retina图片,不过你要保证每张图片都要有对应的retina版本的图片,命名要一致(比如后面都带上@2x),并且都要是相同倍数。

最终我的gulpfile是这样的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
/* 
* @Author: HelKyle
* @Date: 2015-12-09 10:54:27
* @Last Modified by: HelKyle
* @Last Modified time: 2015-12-09 23:57:01
*/

'use strict';


var gulp = require('gulp');
var spritesmith = require('gulp.spritesmith');
var runSequence = require('run-sequence');
var open = require('gulp-open');

var configs = {
//修改图片位置
spritesSource: './src/image/sprites/*.*',
spritesMithConfig: {
//由于图片最终是要放到七牛上,这里的cssOpts用来当成最终scss文件中的变量名,详情看scss.template.mustache
cssOpts: 'spriteSrc',

imgName: 'sprite.png',
cssName: 'sprite.scss',
cssFormat: 'scss',
cssTemplate: 'scss.template.mustache',
algorithm: 'binary-tree',
padding: 8,
cssVarMap: function(sprite) {
sprite.name = 'icon-' + sprite.name
}
},
spritesOutputPath: './built/sprite/'
}

//总命令
gulp.task('sprite', function(callback) {
runSequence(
'sprite:build',
'sprite:images',
'sprite:open',
callback
)
});
//创建精灵图
gulp.task('sprite:build', function() {
var spriteData = gulp.src(configs.spritesSource) // source path of the sprite images
.pipe(spritesmith(
configs.spritesMithConfig
));
spriteData.img.pipe(gulp.dest(configs.spritesOutputPath)); // output path for the sprite
spriteData.css.pipe(gulp.dest(configs.spritesOutputPath)); // output path for the CSS
})
//压缩
gulp.task('sprite:images', function() {
return gulp.src(configs.spritesOutputPath + '/**/*.+(png|jpg|jpeg|gif|svg)')
// Caching images that ran through imagemin
.pipe(imagemin({
interlaced: true,
}))
.pipe(gulp.dest(configs.spritesOutputPath))
});
//打开文件目录
gulp.task('sprite:open', function() {
gulp.src('')
.pipe(open({app: 'Finder', uri: configs.spritesOutputPath}));
})

加入了图片压缩,压缩完自动打开文件夹(mac)等等。
更多参数,你可以去这里

自动化的路还很长

自动化的路还很长,接下来有时间再整理一下自动上传cdn并替换文件路径的。

今天主要就干了这些,好惭愧!但是感觉解放了双手[/淫笑]

纯属个人总结,如果更好的想法,请赐教!拜托了!

如需转载,请注明出处: http://w3ctrain.com / 2015/12/09/generating-sprites-with-gulp/