针对浏览器网页的一些优化规则。
目录
页面优化
静态资源压缩
CSS雪碧图、Base64内联图片
样式置顶、脚本置底
使用外链的css和js
避免空src的图片
避免在html中缩放图片
Preload预加载
CSS优化
选择器
减少选择器的层级
精简页面样式文件,去掉不用的样式
利用css继承减少代码量
属性值为0时,不加单位
JavaScript优化
使用事件委托
DOMContentLoaded
预加载、懒加载
避免全局查找
避免不必要的属性查询
函数节流
最小化语句数
字符串优化
减少回流和重绘
HTTP
浏览器缓存
为什么要减少HTTP请求
页面优化
静态资源压缩
借助构建工具(webpack、gulp)适当压缩图片、脚本及样式等网页静态资源。
CSS雪碧图、base64内联图片
将站内小图标合并成一张图,使用css定位截取对应图标;适当使用内联图片。
样式置顶、脚本置底
页面是一个逐步呈现的过程,样式置顶能更快呈现页面给用户;<script>
标签置顶会阻塞页面后面资源的下载。
使用外链的css和js
多个页面引用公共静态资源,资源复用减少额外的http请求。
避免空src的图片
避免不必要的http请求。
<!-- 空src的图片依然会发起http请求 --><img class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="" alt="image" />
避免在html中缩放图片
图片尽量按需求使用指定规格的尺寸,而不是加载一张大图片再将它缩小。
<!-- 实际图片尺寸为600x300,在html中缩放为了200x100 --><img class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="/static/images/a.png" width="200" height="100" alt="image" />
Preload预加载
给link
标签的rel
设置preload
属性,可以让浏览器在主渲染机制介入前就预加载资源。这种机制可以更早的获取资源且不阻塞页面的初始化。
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Document</title> <link ref="preload" href="style.css" as="style"> <link ref="preload" href="main.js" as="script"> <link ref="stylesheet" href="style.css"></head><body> <script class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="main.js"></script></body></html>
例子中预加载了css和js文件,在之后的页面渲染中,一旦使用它们就会立即调用。
可指定as
的类型加载不同类型的资源。
style
script
video
audio
image
font
document
...
该方式也可跨域预加载资源,设置crossorigin
属性即可。
<link rel="preload" href="fonts/cicle_fina-webfont.woff2" as="font" type="font/woff2" crossorigin="anonymous">
CSS
选择器
选择器的优先级从高到低排列为:
ID选择器
类选择器
标签选择器
相邻选择器
h1 + p{ margin-top: 15px; }
选择紧接在h1
元素后出现的段落,h1
和p
元素拥有共同的父元素。
子选择器
h1 > strong {color:red;}
后代选择器
h1 em {color:red;}
通配符选择器
属性选择器
*[title] {color:red;}img[alt] {border: 5px solid red;}
伪类选择器
选择器使用经验:
优先选择类选择器,可替代多层标签选择器;
慎用ID选择器,虽然它效率高,但是在页面中是唯一的,不利于团队协作和维护;
合理利用选择器的继承性;
避免css表达式。
减少选择器的层级
建立在上一条选择器的优先级之上,应尽量避免多层次的选择器嵌套,最好不要超过3层。
.container .text .logo{ color: red; }/*改成*/.container .text-logo{ color: red; }
精简页面样式文件,去掉不用的样式
浏览器会进行多余的样式匹配,影响渲染时间,另外样式文件过大也会影响加载速度。
利用css继承减少代码量
利用css的可继承属性,父元素设置了样式,子元素就不用再设置。
常见的可以继承的属性比如:color
,font-size
,font-family
等;不可继承的比如:position
,display
,float
等。
属性值为0时,不加单位
css属性值为0时,可不加单位,减少代码量。
.text{ width: 0px; height: 0px; }/*改成*/.text{ width: 0; height: 0; }
JavaScript
使用事件委托
给多个同类DOM元素绑定事件使用事件委托。
<ul id="container"> <li class="list">1</li> <li class="list">2</li> <li class="list">3</li></ul>
// 不合理的方式:给每个元素都绑定click事件$('#container .list').on('click', function() { var text = $(this).text(); console.log(text); });// 事件委托方式:利用事件冒泡机制将事件统一委托给父元素$('#container').on('click', '.list', function() { var text = $(this).text(); console.log(text); });
需要注意的是,虽然使用事件委托时都可以将事件委托给document
来做,但这是不合理的,一个是容易造成事件误判,另一个是作用域链查找效率低。应该选择最近的父元素作为委托对象。
使用事件委托除了性能上更优,动态创建的DOM元素也不需要再绑定事件。
DOMContentLoaded
可在DOM元素加载完毕(DOMContentLoaded
)后开始处理DOM树,不必等到所有图片资源下载完后再处理。
// 原生javascriptdocument.addEventListener("DOMContentLoaded", function(event) { console.log("DOM fully loaded and parsed"); }, false);// jquery$(document).ready(function() { console.log("ready!"); });// $(document).ready()的简化版$(function() { console.log("ready!"); });
预加载和懒加载
预加载
利用浏览器空闲时间预先加载将来可能会用到的资源,如图片、样式、脚本。
无条件预加载
一旦触发,立即获取将来需要用到的资源。
图片资源预加载。(3种实现图片预加载的方式)。
基于用户行为的预加载
对于用户行为可能进行的操作进行判断,预先加载将来可能需要用到的资源。
当用户在搜索输入框输入时,预先加载搜索结果页可能用到的资源;
当用户去操作一个Tab选项卡时,默认显示其中一个,当要去点击(
click
)其他选项时,在鼠标hover
时,就可先加载将来会用到的资源;
懒加载
除页面初始化需要的内容或组件之外,其他都可以延迟加载,如剪切图片的js库、不在可视范围的图片等等。
图片懒加载。(判断图片是否在可视区域范围内,若在,则将真实路径赋给图片)
避免全局查找
任何一个非局部变量在函数中被使用超过一次时,都应该将其存储为局部变量。
function updateUI(){ var imgs = document.getElementsByTagName("img"); for (var i=0, len=imgs.length; i < len; i++){ imgs[i].title = document.title + " image " + i; } var msg = document.getElementById("msg"); msg.innerHTML = "Update complete."; }
在上面函数中多次使用到document
全局变量,尤其在for循环中。因此将document
全局变量存储为局部变量再使用是更优的方案。
function updateUI(){ var doc = document; var imgs = doc.getElementsByTagName("img"); for (var i=0, len=imgs.length; i < len; i++){ imgs[i].title = doc.title + " image " + i; } var msg = doc.getElementById("msg"); msg.innerHTML = "Update complete."; }
值得注意的一点是,在javascript代码中,任何没有使用var
声明的变量都会变为全局变量,不正当的使用会带来性能问题。
避免不必要的属性查询
使用变量和数组要比访问对象上的属性更有效率,因为对象必须在原型链中对拥有该名称的属性进行搜索。
// 使用数组var values = [5, 10];var sum = values[0] + values[1]; alert(sum);// 使用对象var values = { first: 5, second: 10};var sum = values.first + values.second; alert(sum);
上面代码中,使用对象属性来计算。一次两次的属性查找不会造成性能问题,但若需要多次查找,如在循环中,就会影响性能。
在获取单个值的多重属性查找时,如:
var query = window.location.href.substring(window.location.href.indexOf("?"));
应该减少不必要的属性查找,将window.location.href
缓存为变量。
var url = window.location.href;var query = url.substring(url.indexOf("?"));
函数节流
假设有一个搜索框,给搜索框绑定onkeyup
事件,这样每次鼠标抬起都会发送请求。而使用节流函数,能保证用户在输入时的指定时间内的连续多次操作只触发一次请求。
<input type="text" id="input" value="" />
// 绑定事件document.getElementById('input').addEventListener('keyup', function() { throttle(search); }, false);// 逻辑函数function search() { console.log('search...'); }// 节流函数function throttle(method, context) { clearTimeout(method.tId); method.tId = setTimeout(function() { method.call(context); }, 300); }
节流函数的应用场景不局限搜索框,比如页面的滚动onscroll
,拉伸窗口onresize
等都应该使用节流函数提升性能。
最小化语句数
语句数量的多少也是影响操作执行速度的因素。
将多个变量声明合并为一个变量声明
// 使用多个var声明var count = 5;var color = "blue";var values = [1,2,3];var now = new Date();// 改进后var count = 5, color = "blue", values = [1,2,3], now = new Date();
改进的版本是只使用一个var
声明,由逗号隔开。当变量很多时,只使用一个var
声明要比单个var
分别声明快很多。
使用数组和对象字面量
使用数组和对象字面量的方式代替逐条语句赋值的方式。
var values = new Array(); values[0] = 123; values[1] = 456; values[2] = 789;// 改进后var values = [123, 456, 789];
var person = new Object(); person.name = "Jack"; person.age = 28; person.sayName = function(){ alert(this.name); };// 改进后var person = { name : "Jack", age : 28, sayName : function(){ alert(this.name); } };
字符串优化
字符串拼接
早期浏览器未对加号拼接字符串方式优化。由于字符串是不可变的,就意味着要使用中间字符串来存储结果,因此频繁的创建和销毁字符串是导致它效率低下的原因。
var text = "Hello"; text+= " "; text+= "World!";
把字符串添加到数组中,再调用数组的join
方法转成字符串,就避免了使用加法运算符。
var arr = [], i = 0; arr[i++] = "Hello"; arr[i++] = " "; arr[i++] = "World!";var text = arr.join('');
现在的浏览器都对字符串加号拼接做了优化,所以在大多数情况下,加法运算符还是首选。
减少回流和重绘
在浏览器渲染过程中,涉及到回流和重绘,这是一个损耗性能的过程,应注意在脚本操作时减少会触发回流和重绘的动作。
回流:元素的几何属性发生了变化,需要重新构建渲染树。渲染树发生变化的过程,就叫回流;
重绘:元素的几何尺寸没有变化,某个元素的CSS样式(背景色或颜色)发生了变化。
触发重排或重绘的操作有哪些?
调整窗口大小
修改字体
增加或者移除样式表
内容变化,比如用户在
<input/>
框中输入文字操作
class
属性脚本操作DOM(增加、删除或修改DOM元素)
计算
offsetWidth
和offsetHeight
属性设置
style
属性的值
如何减少重排和重绘,提升网页性能?
1、脚本操作DOM元素
将DOM元素设置为
display:none
,设置过程中会触发一次回流,但之后可以随意改动,修改完后再显示;将元素
clone
到内存中再进行操作,修改完后重新替换元素。
2、修改元素的样式
尽量批量修改,而不是逐条修改;
预先设定好
id
、class
,再设置元素的className
。
3、为元素添加动画时将元素CSS样式设为position:fixed
或position:absolute
,元素脱离文档流后不会引起回流。
4、在调整窗口大小、输入框输入、页面滚动等场景时使用节流函数(上面已提到过)。
HTTP
浏览器缓存
合理设置浏览器缓存是网页优化的重要手段之一。
Expires 和 Cache-Control
Expires出自HTTP1.0,Cache-Control出自HTTP1.1,同时设置两者时,Cache-Control 会覆盖 Expires。
Expires指定的是实际过期日期而不是秒数。但Expires存在一些问题,如服务器时间不同步或不准确。所以最好使用剩余秒数而不是绝对时间来表达过期时间。
Cache-Control可设置max-age值,单位秒,指定缓存过期时间。如:Cache-Control: max-age=3600。
ETag 和 Last-Modified
ETag 和 Last-Modified都由服务器返回在response headers中,其中ETag的优先级比Last-Modified高,也就是说服务器会优先判断ETag的值。
ETag是附加到文档上的任意标签,可能是文档的序列号或版本号,或者是文档内容的校验等。当文档改变时ETag值也会随之改变。与ETag相关的是 If-None-Match,当浏览器发起请求时,会在If-None-Match字段携带ETag的值发给服务器;
Last-Modified是文档在服务器端最后被修改的时间。与Last-Modified相关的是If-Modified-Since,当浏览器发起请求时,会在If-Modified-Since字段携带Last-Modified的值发送给服务器。
强缓存和协商缓存
缓存的类型强缓存和协商缓存。两者区别是,强缓存不会向服务器发请求,而协商缓存会发请求,匹配成功返回304 Not Modified,匹配不成功返回200;浏览器会先校验强缓存,若强缓存未命中,再进行协商缓存校验。
如何配置浏览器缓存
在web服务器的返回响应中添加
Expires
和Cache-Control
;在nginx或apache的配置文件中配置
Expires
和Cache-Control
。
为什么要减少HTTP请求
在性能优化中减少http请求的措施占了很大部分,比如:使用css雪碧图代替多张图片的请求、避免空src的图片、使用内联图片、使用外链的css和js、缓存等。
从输入URL到页面加载完成的过程包括:
DNS解析
TCP连接
HTTP请求与响应
浏览器渲染页面
关闭连接
一个完整的http请求要经历这些过程,它是耗时耗资源的,因此减少请求数就变得很有必要。
参考资料:
《高性能网站建设vs高性能网站建设进阶指南》
《JavaScript高级程序设计(第三版)》
《HTTP权威指南》
《Best Practices for Speeding Up Your Web Site》
作者:__MYSTERY
链接:https://www.jianshu.com/p/e17a872a0ec5
共同学习,写下你的评论
评论加载中...
作者其他优质文章