1、合并图标,减少网络请求
合并图标是减少网络请求的常见的优化手段,网页中的小图标特征是体积小、数量多,而浏览器同时发起的并行请求数量又是有限制的,所以这些小图标会严重的影响网页的加载速度,阻碍关键内容的请求和呈现
sprite图
合并sprite图是慢工细活儿,并没有特别大的技术含量,但却是每个前端开发都必须掌握的技术。gulp.spritesmith插件。
// 构建视图文件
gulp.task('sprites', function() {
var spriteData = gulp.src(config.src)
.pipe(plumber(handleErrors))
.pipe(newer(config.imgDest))
.pipe(logger({ showChange: true }))
.pipe(spritesmith({
cssName: 'sprites.css',
imgName: 'sprites.png',
cssTemplate: path.resolve('./gulp/lib/template.css.handlebars')
}));
var imgStream = spriteData.img
.pipe(buffer())
.pipe(gulp.dest(config.imgDest));
var cssStream = spriteData.css
.pipe(gulp.dest(config.cssDest));
return merge([imgStream, cssStream]);
});
sprite图不适合移动端的响应式场景。
iconfont字体文件
iconfont字体文件是用字体编码的形式来实现图标效果,既然是文字,那就可以随意设置颜色设置大小,相对来说比sprite方案更好。但是它只适用于纯色图标。推荐使用 阿里巴巴矢量图标库
2、用base64代替图片
场景:适用于图片大小小于2KB,页面上引用图片总数不多的情况 原理:将图片转换为base64编码字符串inline到页面或css中 优势:减少http的请求次数,并可以放到后台数据库中,只传输字符串,有较多的构建工具可以直接实现 劣势:这种方法仅限于图片总数较少,而且图片大小小于2KB的情况。否则图片字符串会变得很长很长
3、图片处理
1.图片懒加载
图片是网页中流量占比最多的部分,也是需要重点优化的部分。
2.图片压缩
好用的网站:
https://tinypng.com/
https://zhitu.isux.us/
http://alloyteam.github.io/gopng/
4、JS/CSS按需打包
按需打包是webpack独特的优势,如果有需要通过此种方式来管理模块之间的依赖关系,强烈推荐引入!
插件化
:webpack本身非常灵活,提供了丰富的插件接口。基于这些接口,webpack开发了很多插件作为内置功能。速度快
:webpack使用异步IO以及多级缓存机制。所以webpack的速度是很快的,尤其是增量更新。丰富的Loaders
:loaders用来对文件做预处理。这样webpack就可以打包任何静态文件。高适配性
:webpack同时支持AMD
/CommonJs
/ES6
模块方案。webpack会静态解析你的代码,自动帮你管理他们的依赖关系。此外,webpack对第三方库的兼容性很好。代码拆分
:webpack可以将你的代码分片,从而实现按需打包。这种机制可以保证页面只加载需要的JS代码,减少首次请求的时间。优化
:webpack提供了很多优化机制来减少打包输出的文件大小,不仅如此,它还提供了hash机制,来解决浏览器缓存问题。开发模式友好
:webpack为开发模式也提供了很多辅助功能。比如SourceMap、热更新等。使用场景多
:webpack不仅适用于web应用
场景,也适用于Webworkers
、Node.js
场景
webpack 如何最佳配置?
webpack官方提供的配置方法是通过module.exports返回一个json,但是这种场景不灵活,不能适配多种场景。webpack.config.production.js/webpack.config.development.js
,然后不同场景下,使用不同的配置文件。
相对来说,第一种更简单,但是重复配置多;第二种更灵活,推荐第二种方式。
module.exports =
function
(env) {
return
{
context: config.context,
entry: config.src,
output: {
path: path.join(config.jsDest, project),
filename:
'[name].js'
,
chunkFilename:
'[name].[chunkhash:8].js'
,
publicPath:
'/assets/'
+ project +
'/'
},
devtool:
"eval"
,
watch:
false
,
profile:
true
,
cache:
true
,
module: {
loaders: getLoaders(env)
},
resolve: {
alias: getAlias(env)
},
plugins: getPlugins(env)
};
}
其中关键的配置这儿简单介绍如下,后续的系列博客会根据每个点详细介绍。context
:上下文。entry
:入口文件,是所有依赖关系的入口,webpack从这个入口开始静态解析,分析模块之间的依赖关系。output
:打包输出的配置。devtools
:SourceMap选项,便于开发模式下调试。watch
:监听模式,增量更新,开发必备!profile
:优化。cache
:webpack构建的过程中会生成很多临时的文件,打开cache可以让这些临时的文件缓存起来,从而更快的构建。module.loaders
:如前文介绍,loaders用来对文件做预处理。这样webpack就可以打包任何静态文件。resolve.alias
:模块别名,这样可以更方便的引用模块。plugins
:如前文介绍,webpack的一些内置功能均是以插件的形式提供。
webpack和gulp区别:
gulp是基于流的构建工具:all in one的打包模式,输出一个js文件和一个css文件,优点是减少http请求,万金油方案。
如何减小请求大小?
1、JS/CSS/HTML压缩
这也是常规手段,就不介绍太多,主要的方式有:
简单介绍一下JS/CSS/HTML压缩方式和一些注意事项
JS压缩
JS压缩
:使用webpack的UglifyJsPlugin
插件,同时做一些代码检测。
new
webpack.optimize.UglifyJsPlugin({
mangle: {
except: [
'$super'
,
'$'
,
'exports'
,
'require'
]
}
})
CSS压缩
CSS压缩
:使用cssnano压缩,同时使用postcss做一些自动化操作,比如自动加前缀、属性fallback支持、语法检测等。
var
postcss = [
cssnano({
autoprefixer:
false
,
reduceIdents:
false
,
zindex:
false
,
discardUnused:
false
,
mergeIdents:
false
}),
autoprefixer({
browers: [
'last 2 versions'
,
'ie >= 9'
,
'> 5% in CN'
]
}),
will_change,
color_rgba_fallback,
opacity,
pseudoelements,
sorting
];
HTML压缩
HTML压缩
:使用htmlmin压缩HTML,同时对不规范的HTML写法纠正。
// 构建视图文件-build版本
gulp.task(
'build:views'
, [
'clean:views'
],
function
() {
return
streamqueue({ objectMode:
true
},
gulp.src(config.commonSrc, { base:
'src'
}),
gulp.src(config.layoutsSrc, { base:
'src'
}),
gulp.src(config.pagesSrc, { base:
'src/pages'
}),
gulp.src(config.componentsSrc, { base:
'src'
})
)
.pipe(plumber(handleErrors))
.pipe(logger({ showChange:
true
}))
.pipe(preprocess({ context: { PROJECT: project } }))
.pipe(gulpif(
function
(file) {
if
(file.path.indexOf(
'.html'
) != -1) {
return
true
;
}
else
{
return
false
;
}
}, htmlmin({
removeComments:
true
,
collapseWhitespace:
true
,
minifyJS:
true
,
minifyCSS:
true
,
ignoreCustomFragments: [/<%[\s\S]*?%>/,
/<\?[\s\S]*?\?>/,
/<meta[\s\S]*?name=
"viewport"
[\s\S]*?>/]
})))
.pipe(gulp.dest(config.dest));
});
2、gzip压缩
gzip压缩也是比较常规的优化手段。前端并不需要做什么实际的工作,后台配置下服务器就行,效果非常明显。如果你发现你的网站还没有配置gzip,那么赶紧行动起来吧。
gzip压缩效果
那么gzip压缩的效果有多明显呢?保守估计,在已经完成JS/CSS/HTML压缩的基础上,还能降低60-80%左右的大小。
但需要注意,gzip压缩会消耗服务器的性能,不能过度压缩。所以推荐只对JS/CSS/HTML等资源做gzip压缩。图片的话,托管到第三方的图片建议开启gzip压缩,托管到自己应用服务器的图片不建议开启gzip压缩。
3、JS/CSS按需加载
和前面提到的按需打包不同。JS/CSS按需打包
是预编译发生的事情,保证只打包当前页面相关的逻辑。JS/CSS按需加载
是运行时发生的事情,保证只加载当前页面第一时间使用到的逻辑。
那么怎么实现按需加载呢?好奇心日报使用webpack提供的require
及require.ensure
方法来实现按需加载,值得一提的是,除了指定的按需加载文件列表,webpack还会自动解析回调函数的依赖及指定列表的深层次依赖,并最终打包成一个文件。
webpack按需加载
上诉代码的实现效果是:只有当点击登录按钮的时候,才会去加载登录相关的JS/CSS资源。资源在加载成功后自动执行。
4、图片压缩,jpg优化
托管到应用服务器的图片压缩
可以手动处理,也可以通过gulp子任务来处理。tinypng ,压缩效果极好。gulp-imagemin插件,自动化处理,效果也还不错。
// 图片压缩
gulp.task('images', function() {
return gulp.src(config.src)
.pipe(plumber(handleErrors))
.pipe(newer(config.dest))
.pipe(logger({ showChange: true }))
.pipe(imagemin()) // 压缩
.pipe(gulp.dest(config.dest));
});
托管到第三方平台的图片压缩
比如七牛云平台,他们会有一套专门的方案来对图片压缩,格式转换,裁剪等。只需要在url后面加上对应的参数即可,虽然偶尔会有一些小bug,但整体来说,托管方案比用自家应用服务器方案更优。
改变参数,实现不同程度的压缩
jpg优化
除了对图片进行压缩之外,对透明图床没有要求的场景,强烈建议将png转换为jpg,效果很明显!
png转jpg,体积相差八倍
5、webp优化 & srcset优化
webp优化
粗略看一眼,卧槽,兼容性这么差,也就安卓浏览器及chrome浏览器对它的支持还算给力。
webp兼容性
另一方面,webp优化能在jpg的基础上再降低近50%的大小。其优化效果明显。此外,如果浏览器支持webpanimation,还能对gif做压缩!
普通图片webp优化
gif图片优化
兼容性差,但效果好!最终好奇心决定尝试一下。
鉴于浏览器对webp的支持比较局限,我们采用渐进升级的方式来优化:对于不支持webp的浏览器,不做处理;对于支持webp的浏览器,将图片src替换成webp格式。
// 检测浏览器是否支持webp
// 之所以没写成回调,是因为即使isSupportWebp=false也无大碍,但却可以让代码更容易维护
(
function
() {
function
webpTest(src, name) {
var
img =
new
Image(),
isSupport =
false
,
className, cls;
img.onload =
function
() {
isSupport = !!(img.height > 0 && img.width > 0);
cls = isSupport ? (
' '
+ name) : (
' no-'
+ name);
className = document.querySelector(
'html'
).className
className += cls;
document.querySelector(
'html'
).className = className.trim();
};
img.onerror =
function
() {
cls = (
' no-'
+ name);
className = document.querySelector(
'html'
).className
className += cls;
document.querySelector(
'html'
).className = className.trim();
};
img.src = src;
}
var
webpSrc =
'data:image/webp;base64,UklGRiQAAABXRUJQVlA4IBgAAAAwAQCdASoB\
AAEAAwA0JaQAA3AA/vuUAAA='
,
webpanimationSrc =
'data:image/webp;base64,UklGRlIAAABXRUJQVlA4WAoAAAA\
SAAAAAAAAAAAAQU5JTQYAAAD/AABBTk1GJgAAAAAAAAAAAA\
AAAAAAAGQAAABWUDhMDQAAAC8AAAAQBxAREYiI/gcA'
;
webpTest(webpSrc,
'webp'
);
webpTest(webpanimationSrc,
'webpanimation'
);
})();
借鉴modernizr,实现了检测webp/webpanimation兼容性的函数,从代码中可以看出,检测原理就是模拟下载对应格式的图片,在异步函数中可以得到兼容性结果。
接下来就是替换url为webp格式
// 获取webp格式的src
function
_getWebpSrc(src) {
var
dpr = Math.round(window.devicePixelRatio || 1),
ratio = [1, 1, 1.5, 2, 2, 2],
elHtml = document.querySelector(
'html'
),
isSupportWebp = (/(^|\s)webp(\s|$)/i).test(elHtml.className),
isSupportWebpAnimation = (/(^|\s)webpanimation(\s|$)/i).test(elHtml.className),
deviceWidth = elHtml.clientWidth,
isQiniuSrc = /img\.qdaily\.com\
//.test(src),
format = _getFormat(src),
isGifWebp, isNotGifWebp, regDetailImg;
if
(!src || !isQiniuSrc || !format || format ==
'webp'
) {
return
src;
}
isNotGifWebp = (format !=
'gif'
&& isSupportWebp);
isGifWebp = (format ==
'gif'
&& isSupportWebpAnimation);
// 根据屏幕分辨率计算大小
src = src.replace(/\/(thumbnail|crop)\/.*?(\d+)x(\d+)[^\/]*\
//ig, function(match, p0, p1, p2) {
if
(dpr > 1){
p1 = Math.round(p1 * ratio[dpr]);
p2 = Math.round(p2 * ratio[dpr]);
match = match.replace(/\d+x\d+/, p1 +
'x'
+ p2)
}
return
match;
});
if
(isNotGifWebp || isGifWebp) {
// 替换webp格式,首页/列表页
src = src.replace(/\/format\/([^\/]*)/ig,
function
(match, p1) {
return
'/format/webp'
;
});
}
}
注意事项
1、window的屏幕像素密度不一定是整数,mac浏览器缩放之后,屏幕像素密度也不是整数。所以获取dpr一定要取整:dpr = Math.round(window.devicePixelRatio || 1);
。ratio = [1, 1, 1.5, 2, 2, 2]
表示:1倍屏使用1倍图,2倍屏使用1.5倍图,3倍屏以上都用2倍图。这儿的规则可以按实际情况来设置。
devicePixelRatio兼容性
srcset兼容性
srcset兼容性
如上所述,在对webp优化的时候,我们顺道模拟实现了srcset:根据屏幕像素密度来设置最适合的图片宽高。
知识点
整体来说,涉及的知识面比较广:包括webpack & gulp的构建系统、图片的webp优化、服务器的gzip配置、浏览器的加载顺序、图片延迟加载方案等等。

长按二维码点选(识别图中二维码)