WebPack 图片处理
前言:在网页开发的过程中,经常需要处理各类图标。以前我们会使用png/jpg图片,压缩完转base64或直接使用。但是这样会出现一个重要的问题,就是我们的图标是模糊的,放大一定系数之后,这种缺陷会越发的明显。有鉴于此,取而代之的是 iconFont 以及 SVG 等技术。本文会比较各类图片处理技术,各自的使用场合,并说明如何结合 Webpack 使用它们进行网页开发。
PNG / JPG 等像素图片格式
使用
webpack
将切完的 PNG/JPG 等像素图片压缩后(tiny png)放入到项目中,利用 webpack url-loader 载入使用即可,配置如下:
{
test: /\.(png|jpe?g|gif)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('img/[name].[hash:7].[ext]')
}
},
此处,options 配置了:
-
limit 设置让 webpack 在处理较小的图片(此处为 10 kb),将其转换成base64字符串
-
name 设置用于配置生成后的文件的命名(此处加入了长度为7的hash串)
CSS
利用 background url 引入使用即可:
/* 定义在元素上 */
.icon-logo {
display: block;
...
background: url(../assets/images/logo.png);
}
/* 定义在伪元素上 */
.icon-logo:before {
content: '';
display: block;
...
background: url(../assets/images/logo.png);
}
PNG
-
适用场景:无损保存含有透明通道的像素图片(无法提供矢量图),若图片较小可直接转码为base64格式
-
优点:无损保存像素图片
-
缺点:文件较大,需压缩处理;像素图片在放大一定的系数后,都会显的模糊
JPG
-
适用场景:有损保存无透明通道的像素图片(无法提供矢量图),若图片较小可直接转码为base64格式。
-
优点:有损保存可以压缩图片大小
-
缺点:较原图有损,同时在放大后,会显的更加模糊
Base64 编码
当图片文件较小时,可以转换成内联的base64格式来使用,使用该方式载入图片有以下优点:
-
无需通过请求加载图片,能够减少大量的图片请求数,减少页面加载时间
-
可用于各类预加载场景Loading图
-
在样式类中内联使用非常方便,删除更新都非常方便,不会产生冗余图片
缺点:
-
base64字符串的大小会比原图大30%左右
-
无法提供对应的图片预览
IconFont
IconFont 是指将多个图标合并起来转换成字体文件,然后像使用文字一样使用它们,可以对这些图标使用很多文字效果。同时IconFont 图标放大后不会模糊,是非常流行一种图片处理技术。
使用
webpack
利用 webpack url-loader 载入:
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
}
}
options 参数含义同上文所述。
CSS
定义 font-family 和对应的样式类来使用:
/* @font-face 定义 IconFont 字体 */
@font-face {
font-family: 'IconFont';
src: url('./fonts/icon-font.eot');
src: url('./fonts/icon-font.eot') format('embedded-opentype'), url('./fonts/icon-font.woff2') format('woff2'), url('./fonts/icon-font.woff') format('woff'), url('./fonts/icon-font.ttf') format('truetype'), url('./fonts/icon-font.svg') format('svg');
font-weight: normal;
font-style: normal;
}
/* 定义公用样式类 */
.icon-font {
display: inline-block;
font: normal normal normal 14px/1 IconFont;
font-size: inherit;
}
/* 具体图标样式类(一般在伪元素中使用) */
.icon-font-edit:before {
content: "\f040";
}
优缺点
优点
-
可以将多个图标 icon 合并成一个字体文件,减少图片请求次数
-
放大不会模糊(矢量图)
-
可以利用部分字体的样式来定制图标(如大小、颜色等)
缺点
-
一般只用于保存各类简易的图标,不支持单个大文件图片
-
需提供对应的矢量文件来生成字体文件,生成起来较繁琐,增删图标都需要进行重新生成
-
不同浏览器支持的字体文件格式不一样,CSS样式中需添加多个字体文件加载源
iconfont.cn
建议多使用 iconfont.cn 网站来生成和管理 IconFont 图标字体文件。
SVG
SVG 是一种网络矢量图片格式,SVG 图片放大不会模糊,同时支持很多矢量图片的操作(如填充、描边、蒙版等),是非常流行的一种图片处理技术,同时其生成和使用非常方便,已经有取代IconFont的趋势。
使用
Vue + Webpack
使用 vue-svg-loader 将 SVG 图片加载成 Vue 组件使用:
{
test: /\.svg$/,
loader: 'vue-svg-loader',
options: {
svgo: {
plugins: [
{
cleanupIDs: {
minify: false
},
},
{
removeViewBox: false
}
]
}
}
},
此处,options中是 vue-svg-loader 的配置信息,plugins 属性定义了使用的 svgo 模块的插件配置,此处禁用了 cleanupIDs 插件的压缩功能以及 viewBox 清除功能(会导致无法使用 width height 属性对 svg 进行缩放)。
说明:vue-svg-loader 使用 svgo 模块来优化和压缩 SVG 图片。svgo 会将 svg 图片内容转换为 js 对象(sax风格),然后利用各类定制插件对该对象进行处理,处理完毕后将该 js 对象再转换为 svg 图片,cleanupIDS 是 svgo 中 id 属性处理插件。
在 vue-svg-loader 的使用过程中,我发现了一个严重的问题,当网页上的 svg 图片较多,并且多个 svg 存在子元素有 id 属性的情况下,这些 id 属性在处理完之后会出现重复的现象,导致一些 svg 图片显示有问题,但是在 github 以及相关平台上未能找到解决方案,于是研究了一下该模块的源码,找出了对应的解决办法。
原因是 svgo 默认使用 cleanupIDs 来清理 svg 元素无用 id属性 或压缩其 id 属性为简单的字符串(如:a, b, c)。但是多个 svg 图片在压缩过程中就会出现重复的 id,在单个页面中出现多个这样的 svg 图片就会导致除了第一个 svg 显示正常以外,其它的 svg 图片无法正常显示。
所以需要禁用 cleanupIDs 插件 minify 压缩功能来确保页面显示正常。
Vue
在组件的 vue 文件中,按照以下形式使用该 SVG 组件:
<template>
<div>
...
<iconLogo class="icon-logo" />
...
</div>
</template>
<script>
import iconLogo from '../assets/images/logo.svg';
export default {
name: 'SVG',
components: {
iconLogo
},
...
}
</script>
<style>
.icon-logo {
fill: #ff4500;
}
</style>
优缺点
优点
-
一般会压缩后内联使用,无需发送图片请求
-
放大不会模糊(矢量图)
-
可以使用大量的矢量图形操作
-
很容易从各类矢量图形设计软件中导出
-
结合 webpack 单个文件模块化处理方便,文件管理也很方便
缺点
-
一般只用于各类图标或简易图形,不支持单个大文件或富表现图片
-
矢量图片压缩空间有限,一般会比像素图片大
iconfont.cn
建议多使用 iconfont.cn 网站来搜索和使用 SVG 图标文件。