webpack-sprites

说明

研究了一通在webpack中生成雪碧图,尝试了两种方式:
方式一:webpack-spritesmith
方式二:postcss-sprites
参考链接:webpack-spritesmithpostcss-sprites
代码地址:demo

webpack-spritesmith

预处理:先将图片生成雪碧图,同时自动生成引用雪碧图的样式文件(css/less等预处理文件),使用时手动使用样式文件中的内容

项目路径

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
webpack.config.js

const path = require('path')
const SpritesmithPlugin = require("webpack-spritesmith")
...
module.exports = {
...
plugins: [
...
new SpritesmithPlugin({
<!-- 需要转雪碧图的原图片路径 -->
src: {
cwd: path.resolve(__dirname, '../src/assets/image/sp/'),
glob: '**/*.png'
},
target: {
image: path.resolve(__dirname, '../src/css/spritesmith-generated/sprite.png'),
css: path.resolve(__dirname, '../src/css/spritesmith-generated/sprite.less')
<!-- 自定义 -->
<!-- css: [[path.resolve(__dirname, '../src/css/spritesmith-generated/sprite.less'),{format: 'function_based_template'}]] -->
},
<!-- customTemplates: {
'function_based_template': templateFunction,
}, -->
apiOptions: {
<!-- 需要使用雪碧图的css文件相对路径,不是生成的sprite.less的相对路径,demo中是base.less文件中使用 -->
cssImageRef: "./spritesmith-generated/sprite.png"
},
<!-- 支持retina, 需要同时存在@1x @2x图片 -->
retina: "@2x"
})
]
}

<!-- 自定义,这种方式是输出写好的class,将class使用在dom中即可 -->
<!-- const templateFunction = function (data) {
var shared = '.ico { background-image: url(I) }'
.replace('I', data.sprites[0].image);

var perSprite = data.sprites.map(function (sprite) {
return '.ico-N { width: Wpx; height: Hpx; background-position: Xpx Ypx; }'
.replace('N', sprite.name)
.replace('W', sprite.width)
.replace('H', sprite.height)
.replace('X', sprite.offset_x)
.replace('Y', sprite.offset_y);
}).join('\n');

return shared + '\n' + perSprite;
}; -->

在配置的target路径下生成图片和样式文件(demo中生成的是less文件),如下

生成了两个雪碧图,一个一倍的一个两倍的,需要注意的是此方法是根据路径将路径下所有图片合成雪碧图,所以不会使用的图片及时删除,避免多余图片拖大小

sprite.less文件没有截全,上部分主要都是变量,主要使用的方法是图中.sprites和.retina-sprites方法,分别处理1@x图片和2@x图片

在base.less文件中使用方式如下(具体使用方法在生成的文件注释中有说明):

1
2
3
4
5
6
7
8
9
10
base.less

@import "./spritesmith-generated/sprite.less";
...
.img1 {
.retina-sprite(@china-group)
}
.img2 {
.sprite(@japan)
}

效果如下:

postcss-sprites

后处理:是postcss-loader的插件,两者差异在于此种方式配置好后自动全部替换成引入雪碧图,不用手动再使用,但是需要自己配置宽高!!(因为只是切换了引用雪碧图以及定位位置,但是div需要自己根据图片大小设置宽高),而webpack-spritesmith是根据图片的大小自动设置了div的宽高(见上图)

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
webpack.config.js

...
module.exports = {
...
module: {
rules: [
...
{
test: /\.less$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders:2
}
},
'postcss-loader',
"less-loader"
]
}
]
}
}
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
postcss.config.js

module.exports = {
ident: 'postcss',
plugins: [
require("autoprefixer")(),
require("cssnano")(),
require("postcss-sprites")({
<!-- 初始雪碧图的位置,未压缩前的图片 -->
spritePath: "dist/assets/imgs/sp/",
<!-- 需要将图片命名为@2x -->
retina: true,
<!-- 根据文件路径过滤,筛选需要转换的图片 -->
filterBy: function(image){
const flag = /\/image\/sp\//.test(image.url)
return flag ? Promise.resolve() : Promise.reject()
},
<!-- 根据文件路径过滤分组,生成多个雪碧图 -->
groupBy: [
function(image){
const flag = /\/sp1\//.test(image.url)
return flag ? Promise.resolve("sprite1") : Promise.reject()
},
function(image){
const flag = /\/sp2\//.test(image.url)
return flag ? Promise.resolve("sprite2") : Promise.reject()
}
]
})
]
}

css的使用按照原图片引用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
base.less

<!-- 需手动根据图片原大小设置宽高,这一点不太好,需要自己计算 -->
.img {
width: 100px;
height: 100px;
float: left
}
.img1 {
background-image: url("../assets/image/sp/sp1/china@2x.png")
}
.img2 {
background-image: url("../assets/image/sp/sp1/japan@2x.png")
}
.img3 {
background-image: url("../assets/image/sp/sp2/korea@2x.png")
}

效果如下:
在设置的目录下生成两个雪碧图,而且因为是替换方式,所以引用的图片才会被合成雪碧图


后记

看到一篇优化移动端使用rem单位进行计算时不同浏览器对小数点的不同处理方式造成Retina屏下的CSS雪碧图问题,方式是改变源码,先马一下