网站前端优化几要素

前言: css

在一样的网络环境下,两个一样能知足你的需求的网站,一个“Duang”的一下就加载出来了,一个纠结了半天才出来,你会选择哪一个?研究代表:用户最满意的打开网页时间是2-5秒,若是等待超过10秒,99%的用户会关闭这个网页。也许这样讲,各位还不会有太多感触,接下来我列举一组数据:Google网站访问速度每慢400ms就致使用户搜索请 求降低0.59%;Amazon每增长100ms网站延迟将致使收入降低1%;雅虎若是有400ms延迟会致使流量降低5-9%。网站的加载速度严重影响了用户体验,也决定了这个网站的生死存亡。html

可能有人会说:网站的性能是后端工程师的事情,与前端并没有多大关系。我只能说,too young too simple。事实上,只有10%~20%的最终用户响应时间是用在从Web服务器获取HTML文档并传送到浏览器的,那剩余的时间去哪儿了?来瞄一下性能黄金法则:前端

只有10%~20%的最终用户响应时间花在了下载HTML文档上。其他的80%~90%时间花在了下载页面中的全部组件上。linux

接下来咱们将研究一下前端攻城狮如何来提升页面的加载速度。web

1、尽可能减小 HTTP 请求后端

有几种常见的方法能切实减小 HTTP 请求:浏览器

一、 合并脚本跟样式文件,如能够把多个 CSS 文件合成一个,把多个 JS 文件合成一个。缓存

二、 CSS Sprites 利用 CSS background 相关元素进行背景图绝对定位,把多个图片合成一个图片。服务器

三、字体图标,如iconfont.cn,font awesome网络

2、使用CDN

CDN(内容发布网络)是一组分布在多个不一样地理位置的Web服务器,用于更加有效地向用户发布内容。在优化性能时,向特定用户发布内容的服务器的选择基于对网络慕课拥堵的测量。例如,CDN可能选择网络阶跃数最小的服务器,或者具备最短响应时间的服务器。

CDN还能够进行数据备份、扩展存储能力,进行缓存,同时有助于缓和Web流量峰值压力。

CDN的缺点:

一、响应时间可能会受到其余网站流量的影响。CDN服务提供商在其全部客户之间共享Web服务器组。

二、若是CDN服务质量降低了,那么你的工做质量也将降低

三、没法直接控制组件服务器

3、添加Expires头

页面的初次访问者会进行不少HTTP请求,可是经过使用一个长久的Expires头,可使这些组件被缓存,下次访问的时候,就能够减小没必要要的HTPP请求,从而提升加载速度。

Web服务器经过Expires头告诉客户端可使用一个组件的当前副本,直到指定的时间为止。例如:

Expires: Fri, 18 Mar 2016 07:41:53 GMT

Expires缺点: 它要求服务器和客户端时钟严格同步;过时日期须要常常检查

HTTP1.1中引入Cache-Control来克服Expires头的限制,使用max-age指定组件被缓存多久。

Cache-Control: max-age=12345600

若同时制定Cache-Control和Expires,则max-age将覆盖Expires头

4、压缩组件

从HTTP1.1开始,Web客户端能够经过HTTP请求中的Accept-Encoding头来表示对压缩的支持

Accept-Encoding: gzip,deflate

若是Web服务器看到请求中有这个头,就会使用客户端列出来的方法中的一种来进行压缩。Web服务器经过响应中的Content-Encoding来通知 Web客户端。

Content-Encoding: gzip

5、将样式表放在头部

将样式表放在文档底部会阻止浏览器中的内容逐步出现。为了不当样式变化时重绘页面元素,浏览器会阻塞内容逐步呈现,形成“白屏”。这源自浏览器的行为:若是样式表仍在加载,构建呈现树就是一种浪费,由于全部样式表加载解析完毕以前务虚会之任何东西

6、将脚本放在底部

更样式表相同,脚本放在底部对于实际页面加载的时间并不能形成太大影响,可是这会减小页面首屏出现的时间,使页面内容逐步呈现。

js的下载和执行会阻塞Dom树的构建(严谨地说是中断了Dom树的更新),因此script标签放在首屏范围内的HTML代码段里会截断首屏的内容。

下载脚本时并行下载是被禁用的——即便使用了不一样的主机名,也不会启用其余的下载。由于脚本可能修改页面内容,所以浏览器会等待;另外,也是为了保证脚本可以按照正确的顺序执行,由于后面的脚本可能与前面的脚本存在依赖关系,不按照顺序执行可能会产生错误。

7、避免CSS表达式

CSS表达式是动态设置CSS属性的一种强大而且危险的方式,它受到了IE5以及以后版本、IE8以前版本的支持。

8、使用外部的JavaScript和CSS

内联脚本或者样式能够减小HTTP请求,按理来讲能够提升页面加载的速度。然而在实际状况中,当脚本或者样式是从外部引入的文件,浏览器就有可能缓存它们,从而在之后加载的时候可以直接使用缓存,而HTML文档的大小减少,从而提升加载速度。

9、减小DNS查找

当咱们在浏览器的地址栏输入网址(譬如: www.linux178.com) ,而后回车,回车这一瞬间到看到页面到底发生了什么呢?

域名解析 --> 发起TCP的3次握手 --> 创建TCP链接后发起http请求 --> 服务器响应http请求,浏览器获得html代码 --> 浏览器解析html代码,并请求html代码中的资源(如js、css、图片等) --> 浏览器对页面进行渲染呈现给用户

10、精简JavaScript/css代码

精简就是从代码中移除没必要要的字符以减小文件大小,下降加载的时间。代码精简的时候会移除没必要要的空白字符(空格,换行、制表符),这样整个文件的大小就变小了。

11、避免重定向

重定向用于将用户从一个URL从新路由到另外一个URL。

经常使用重定向的类型

301:永久重定向,主要用于当网站的域名发生变动以后,告诉搜索引擎域名已经变动了,应该把旧域名的的数据和连接数转移到新域名下,从而不会让网站的排名因域名变动而受到影响。

302:临时重定向,主要实现post请求后告知浏览器转移到新的URL。

304:Not Modified,主要用于当浏览器在其缓存中保留了组件的一个副本,同时组件已通过期了,这是浏览器就会生成一个条件GET请求,若是服务器的组件并无修改过,则会返回304状态码,同时不携带主体,告知浏览器能够重用这个副本,减小响应大小。

12、删除重复脚本

在团队开发一个项目时,因为不一样开发者之间均可能会向页面中添加页面或组件,所以可能相同的脚本会被添加屡次。

重复的脚本会形成没必要要的HTTP请求(若是没有缓存该脚本的话),而且执行多余的JavaScript浪费时间,还有可能形成错误。

如何避免重复脚本呢?

1. 造成良好的脚本组织。重复脚本有可能出如今不一样的脚本包含同一段脚本的状况,有些是必要的,但有些却不是必要的,因此须要对脚本进行一个良好的组织。

2. 实现脚本管理器模块。

十3、配置ETag

实体标签(EntityTag)是惟一标识了一个组件的一个特定版本的字符串,是web服务器用于确认缓存组件的有效性的一种机制,一般可使用组件的某些属性来构造它。

十4、使Ajax可缓存

POST的请求,是不能够在客户端缓存的,每次请求都须要发送给服务器进行处理,每次都会返回状态码200。(能够在服务器端对数据进行缓存,以便提升处理速度)

GET的请求,是能够(并且默认)在客户端进行缓存的,除非指定了不一样的地址,不然同一个地址的AJAX请求,不会重复在服务器执行,而是返回304。

十5、减小 DOM 元素数量

访问DOM元素是有代价的,修改DOM元素则更为昂贵,由于它会致使浏览器从新计算页面的几何变化。 

最坏的状况是在循环中访问修改元素,尤为是对HTML元素集合循环操做。

十6、最小化 iframe 的数量

在写网页的时候,咱们可能会用到iframe,iframe的好处是它彻底独立于父文档。iframe中包含的JavaScript文件访问其父文档是受限的。例如,来自不一样域的iframe不能访问其父文档的Cookie。

即便iframe是空的,其开销也会很高,并且他会阻塞onload事件。因此,咱们应该尽量避免iframe的使用。

十7、杜绝 http 404 错误

十8、CSS选择器优化

一、在谈论选择器优化以前,咱们先简单介绍一下选择器的类型:

ID选择器 : #id;

类选择器: .class

标签选择器: a

兄弟选择器:#id + a 

子选择器: #id > a

后代选择器: #id a

通赔选择器: *

属性选择器: input[type='input']

伪类和伪元素:a:hover , div:after

组合选择器:#id,.class

二、浏览器的匹配规则

#abc > a怎么匹配?  有人可能会觉得:先找到id为abc的元素,再查找子元素为a的元素!!too young,too simple!

其实,浏览器时从右向左匹配选择符的!!!那么上面的写法效率就低了:先查找页面中的全部a标签,在看它的父元素是否是id为abc

知道了浏览器的匹配规则咱们就能尽量的避免开销很大的选择器了:

避免通配规则

除了 * 以外,还包括子选择器、后台选择器等。

而它们之间的组合更加逆天,譬如:li *

浏览器会查找页面的全部元素,而后一层一层地寻找他的祖先,看是否是li,这对可能极大地损耗性能。

不限定ID选择器

ID就是惟一的,不要写成相似div#nav这样,不必。 

不限定class选择器

咱们能够进一步细化类名,譬如li.nav  写成 nav-item

尽可能避免后代选择器

一般后代选择器是开销最高的,若是能够,请使用子选择器代替。

替换子选择器

若是能够,用类选择器代替子选择器,譬如

nav > li 改为 .nav-item

依靠继承

了解那些属性能够依靠继承得来,从而避免重复设定规则。

三、关键选择符

选择器中最右边的选择符成为关键选择符,它对浏览器执行的工做量起主要影响。

举个栗子:

div div li span.class-special

乍一看,各类后代选择器组合,性能确定不能忍。其实仔细一想,浏览器从右向左匹配,若是页面中span.class-special的元素只有一个的话,那影响并不大啊。

反过来看,若是是这样

span.class-special li div div ,尽管span.class-special不多,可是浏览器从右边匹配,查找页面中全部div在层层向上查找,那性能天然就低了。

四、重绘与回流

优化css选择器不只仅提升页面加载时候的效率,在页面回流、重绘的时候也能够获得不错的效果,那么接下来咱们说一下重绘与回流。

4.一、从浏览器的渲染过程谈起

解析HTML构建dom树→构建render树→布局render树→绘制render树

1)构建dom树

根据得到的html代码生成一个DOM树,每一个节点表明一个HTML标签,根节点是document对象。dom树种包含了全部的HTML标签,包括未显示的标签(display:none)和js添加的标签。

2)构建cssom树

将获得全部样式(浏览器和用户定义的css)除去不能识别的(错误的以及css hack),构建成一个cssom树

3)cssom和dom结合生成渲染树,渲染树中不包括隐藏的节点包括(display:none、head标签),并且每一个节点都有本身的style属性,渲染树种每个节点成为一个盒子(box)。注意:透明度为100%的元素以及visibility:hidden的元素也包含在渲染树之中,由于他们会影响布局。

4)浏览器根据渲染树来绘制页面

4.二、重绘(repaint)与回流(reflow)

1)重绘   当渲染树中的一部分或者所有由于页面中某些元素的布局、显示与隐藏、尺寸等改变须要从新构建,这就是回流。每一个页面至少会发生一次回流,在页面第一次加载的时候发生。在回流的时候,浏览器会使渲染树中受到影响的部分失效,并从新构造这部分渲染树,完成回流后,浏览器会从新绘制受影响的部分到屏幕中,该过程成为重绘。

2. 当渲染树中的一些元素须要更新属性,而这些属性不会影响布局,只影响元素的外观、风格,好比color、background-color,则称为重绘。

注意:回流必将引发重绘,而重绘不必定会引发回流。

4.三、回流什么时候发生:

当页面布局和几何属性改变时就须要回流。下述状况会发生浏览器回流:

一、添加或者删除可见的DOM元素;

二、元素位置改变;

三、元素尺寸改变——边距、填充、边框、宽度和高度

四、内容改变——好比文本改变或者图片大小改变而引发的计算值宽度和高度改变;

五、页面渲染初始化;

六、浏览器窗口尺寸改变——resize事件发生时;

4.四、如何影响性能

页面上任何一个结点触发reflow,都会致使它的子结点及祖先结点从新渲染。

每次重绘和回流发生时,浏览器会根据对应的css从新绘制须要渲染的部分,若是你的选择器不优化,就会致使效率下降,因此优化选择器的重要性可见一斑。

相关文章
相关标签/搜索