盒子
文章目录
  1. Postcss Sprites后处理
  2. SpritesmithPlugin

webpack自动雪碧图生成

前端项目中自动生成雪碧图节省了我们很多的时间, 原来做这些工作比较依赖compass, 但是在webpack项目中如果只为了雪碧图引入compass有点太过笨重,这里总结几个使用webpack就能生成雪碧图的方法。

Postcss Sprites后处理

postcss后处理是一个很强大的处理css的工具,跟sass这些预处理工具不同,postcss做为后处理工具,需要我们用loader处理sass后再处理,在postcss里我们做很多事,比如autoprefix,preces,合并图片甚至是一些兼容调整或者px转换em都以支持,像vue-loader等这样的框架文件loader都已经内置了postcss,只要简单的配置就可以使用。

这里我们用autoprefixer简单介绍一下postcss的用法:

install: npm install postcss-loader --save-dev

usage:

1
2
3
4
5
6
7
8
9
module: {
loaders: [
{ test: /\.js$/, loader: 'babel-loader'},
{ test: /\.css$/,loader: 'style-loader!css-loader!postcss-loader'}
]
},
postcss: function () {
return [autoprefixer];
}

同样我们可以在postcss里简单配置一个sprites

1
2
3
4
5
6
7
8
9
10
11
12
var postcssSprites = require('postcss-sprites');

postcss: function () {
return [postcssSprites(
{ stylesheetPath: './src',
spritePath: './src/images/gen/sprite.png',
retina: true,
padding: 3,
filterBy: function(image){return /\/sp\//gi.test(image.url)}
}
)]
}

这个简单的例子里先要告诉了postcss我们的style文件的地址,生成雪碧图的地址,是否需要retina支持,padding可以设置图片之间的空隙,filterBy可以用来排除一些我们不需要合成雪碧图的文件。

我们也可以看一个复杂的例子来自[webpack之postcss集成]

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
//雪碧图相关代码
let spritesConfig = sprites({
retina: true,//支持retina,可以实现合并不同比例图片
verbose: true,
spritePath: './public/images/',//雪碧图合并后存放地址
stylesheetPath: './public',
basePath: './',
filterBy: function (image) {
//过滤一些不需要合并的图片,返回值是一个promise,默认有一个exist的filter
//
if (image.url.indexOf('/images/sprites/') === -1) {
return Promise.reject();
}
return Promise.resolve();
},
groupBy: function (image) {
//将图片分组,可以实现按照文件夹生成雪碧图
return spritesGroupBy(image);
},
hooks: {
onUpdateRule: function (rule, comment, image) {
//更新生成后的规则,这里主要是改变了生成后的url访问路径
return spritesOnUpdateRule(true, rule, comment, image);
},
onSaveSpritesheet: function(opts, groups) {
return spritesOnSaveSpritesheet(true, opts, groups);
}
}
});

let groups = /\/images\/sprites\/(.*?)\/.*/gi.exec(image.url);
let groupName = groups ? groups[1] : group;
image.retina = true;
image.ratio = 1;
if (groupName) {
let ratio = /@(\d+)x$/gi.exec(groupName);
if (ratio) {
ratio = ratio[1];
while (ratio > 10) {
ratio = ratio / 10;
}
image.ratio = ratio;
}
}
return Promise.resolve(groupName);
}

export function spritesOnUpdateRule(isDev, rule, comment, image){
var spriteUrl = image.spriteUrl;
image.spriteUrl = '/public/' + spriteUrl;
postcssSprites.updateRule(rule, comment, image);
}

export function spritesOnSaveSpritesheet(isDev, opts, groups) {
let file = postcssSprites.makeSpritesheetPath(opts, groups);
return file;
}

我们在sass或者别的style file中使用起来也很简单,只要这样

background: url(images/sp/red-sun@2x.png) no-repeat 0 0

基本跟我们设置普通背景图没有区别,具体的一些options可以参考postcss-sprites

SpritesmithPlugin

当然也有很多人不喜欢后处理的方式(比如我),我们的webpack其实也可以通过plugin来处理这些图片,特别是我们还可以获得单个图片的高宽,在一些我们需要让图片居中的场景特别合适,废话不多说,直接看栗子!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var SpritesmithPlugin = require('webpack-spritesmith');
plugins: [
new SpritesmithPlugin({
src: {
cwd: './src/assets/sp/',
glob: '*.png'
},
target: {
image: './src/assets/gen/sprite.png',
css: './src/style/mixins/_sprite.scss'
},
apiOptions: {
cssImageRef: '../assets/gen/sprite.png'
},
spritesmithOptions: {
algorithm: 'top-down'
}
})
]

在这个例子里面,我们设置了src的目录,并且只选择png文件。然后我们的target有两个,一个是生成的雪碧图地址,另外一个是生成用来引用文件(这个我们等会解释),api地址可以写一个src中入口css文件引用的相对地址用来定位,options提供了丰富的配置,这里的top-down就可以生成从上排到下一列的雪碧图用来处理一些需要repeat的情况。

那么我们怎么引用生成的雪碧图呢,我们可以看下target里的css对应的文件:

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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
/*
SCSS variables are information about icon's compiled state, stored under its original file name

.icon-home {
width: $icon-home-width;
}

The large array-like variables contain all information about a single icon
$icon-home: x y offset_x offset_y width height total_width total_height image_path;

At the bottom of this section, we provide information about the spritesheet itself
$spritesheet: width height image $spritesheet-sprites;
*/
$angle-down-name: 'angle-down';
$angle-down-x: 0px;
$angle-down-y: 0px;
$angle-down-offset-x: 0px;
$angle-down-offset-y: 0px;
$angle-down-width: 12px;
$angle-down-height: 6px;
$angle-down-total-width: 24px;
$angle-down-total-height: 179px;
$angle-down-image: '../assets/gen/sprite.png';
$angle-down: (0px, 0px, 0px, 0px, 12px, 6px, 24px, 179px, '../assets/gen/sprite.png', 'angle-down', );
$angle-up-name: 'angle-up';
$angle-up-x: 0px;
$angle-up-y: 6px;
$angle-up-offset-x: 0px;
$angle-up-offset-y: -6px;
$angle-up-width: 12px;
$angle-up-height: 6px;
$angle-up-total-width: 24px;
$angle-up-total-height: 179px;
$angle-up-image: '../assets/gen/sprite.png';
$angle-up: (0px, 6px, 0px, -6px, 12px, 6px, 24px, 179px, '../assets/gen/sprite.png', 'angle-up', );
$angle-up-green-name: 'angle-up-green';
$angle-up-green-x: 0px;
$angle-up-green-y: 12px;
$angle-up-green-offset-x: 0px;
$angle-up-green-offset-y: -12px;
$angle-up-green-width: 13px;
$angle-up-green-height: 7px;
$angle-up-green-total-width: 24px;
$angle-up-green-total-height: 179px;
$angle-up-green-image: '../assets/gen/sprite.png';
$angle-up-green: (0px, 12px, 0px, -12px, 13px, 7px, 24px, 179px, '../assets/gen/sprite.png', 'angle-up-green', );
$checkbox-checked-name: 'checkbox-checked';
$checkbox-checked-x: 0px;
$checkbox-checked-y: 19px;
$checkbox-checked-offset-x: 0px;
$checkbox-checked-offset-y: -19px;
$checkbox-checked-width: 20px;
$checkbox-checked-height: 20px;
$checkbox-checked-total-width: 24px;
$checkbox-checked-total-height: 179px;
$checkbox-checked-image: '../assets/gen/sprite.png';
$checkbox-checked: (0px, 19px, 0px, -19px, 20px, 20px, 24px, 179px, '../assets/gen/sprite.png', 'checkbox-checked', );
$checkbox-disable-name: 'checkbox-disable';
$checkbox-disable-x: 0px;
$checkbox-disable-y: 39px;
$checkbox-disable-offset-x: 0px;
$checkbox-disable-offset-y: -39px;
$checkbox-disable-width: 20px;
$checkbox-disable-height: 20px;
$checkbox-disable-total-width: 24px;
$checkbox-disable-total-height: 179px;
$checkbox-disable-image: '../assets/gen/sprite.png';
$checkbox-disable: (0px, 39px, 0px, -39px, 20px, 20px, 24px, 179px, '../assets/gen/sprite.png', 'checkbox-disable', );
$star-name: 'star';
$star-x: 0px;
$star-y: 59px;
$star-offset-x: 0px;
$star-offset-y: -59px;
$star-width: 24px;
$star-height: 20px;
$star-total-width: 24px;
$star-total-height: 179px;
$star-image: '../assets/gen/sprite.png';
$star: (0px, 59px, 0px, -59px, 24px, 20px, 24px, 179px, '../assets/gen/sprite.png', 'star', );
$radio-checked-name: 'radio-checked';
$radio-checked-x: 0px;
$radio-checked-y: 79px;
$radio-checked-offset-x: 0px;
$radio-checked-offset-y: -79px;
$radio-checked-width: 20px;
$radio-checked-height: 20px;
$radio-checked-total-width: 24px;
$radio-checked-total-height: 179px;
$radio-checked-image: '../assets/gen/sprite.png';
$radio-checked: (0px, 79px, 0px, -79px, 20px, 20px, 24px, 179px, '../assets/gen/sprite.png', 'radio-checked', );
$radio-disable-name: 'radio-disable';
$radio-disable-x: 0px;
$radio-disable-y: 99px;
$radio-disable-offset-x: 0px;
$radio-disable-offset-y: -99px;
$radio-disable-width: 20px;
$radio-disable-height: 20px;
$radio-disable-total-width: 24px;
$radio-disable-total-height: 179px;
$radio-disable-image: '../assets/gen/sprite.png';
$radio-disable: (0px, 99px, 0px, -99px, 20px, 20px, 24px, 179px, '../assets/gen/sprite.png', 'radio-disable', );
$radio-name: 'radio';
$radio-x: 0px;
$radio-y: 119px;
$radio-offset-x: 0px;
$radio-offset-y: -119px;
$radio-width: 20px;
$radio-height: 20px;
$radio-total-width: 24px;
$radio-total-height: 179px;
$radio-image: '../assets/gen/sprite.png';
$radio: (0px, 119px, 0px, -119px, 20px, 20px, 24px, 179px, '../assets/gen/sprite.png', 'radio', );
$star-solid-name: 'star-solid';
$star-solid-x: 0px;
$star-solid-y: 139px;
$star-solid-offset-x: 0px;
$star-solid-offset-y: -139px;
$star-solid-width: 24px;
$star-solid-height: 20px;
$star-solid-total-width: 24px;
$star-solid-total-height: 179px;
$star-solid-image: '../assets/gen/sprite.png';
$star-solid: (0px, 139px, 0px, -139px, 24px, 20px, 24px, 179px, '../assets/gen/sprite.png', 'star-solid', );
$checkbox-name: 'checkbox';
$checkbox-x: 0px;
$checkbox-y: 159px;
$checkbox-offset-x: 0px;
$checkbox-offset-y: -159px;
$checkbox-width: 20px;
$checkbox-height: 20px;
$checkbox-total-width: 24px;
$checkbox-total-height: 179px;
$checkbox-image: '../assets/gen/sprite.png';
$checkbox: (0px, 159px, 0px, -159px, 20px, 20px, 24px, 179px, '../assets/gen/sprite.png', 'checkbox', );
$spritesheet-width: 24px;
$spritesheet-height: 179px;
$spritesheet-image: '../assets/gen/sprite.png';
$spritesheet-sprites: ($angle-down, $angle-up, $angle-up-green, $checkbox-checked, $checkbox-disable, $star, $radio-checked, $radio-disable, $radio, $star-solid, $checkbox, );
$spritesheet: (24px, 179px, '../assets/gen/sprite.png', $spritesheet-sprites, );

/*
The provided mixins are intended to be used with the array-like variables

.icon-home {
@include sprite-width($icon-home);
}

.icon-email {
@include sprite($icon-email);
}

Here are example usages in HTML:

`display: block` sprite:
<div class="icon-home"></div>

`display: inline-block` sprite:
<img class="icon-home" />
*/
@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);
}
}
}

这样大家就懂了,它生成了大量的scss(或者其它格式)的变量和mixin,我们就可以通过import这个文件,然后@include sprite($star);这样很方便的去使用。

项目github地址webpack-spritesmith

具体的options使用可以参考spritesmith