CSS如何進行效能最佳化?以下這篇文章跟大家介紹一些CSS效能優化的小技巧,希望對大家有幫助!
隨著網路發展至今,對於網站來說,效能顯的越來越重要了,CSS作為頁面渲染和內容展現的重要環節,影響著使用者對整個網站的第一體驗。所以,我們需要重視與CSS相關的效能優化。 【推薦學習:css影片教學】
專案開發初期我們可能因為各種原因(很大一部分原因是因為專案工期,產品往往把專案上線時間卡的死死的,根本不聽你說的什麼性能優化),怎麼寫的舒服就怎麼來,對於性能優化我們常常在項目完成時才去考慮,經常被推遲到項目的末期,甚至到暴露出嚴重的性能問題時才進行性能優化。
為了更避免這種情況,首先要重視起性能優化相關的工作,將其貫穿到整個產品設計與開發中。其次,就是了解效能相關的內容,在專案開發過程中,自然而然地進行效能最佳化。
想要最佳化CSS的效能,我們首先需要了解CSS的渲染規則,CSS選擇器是從右向左進行配對的
來看個範例:
.nav h3 a{font-size: 14px;}复制代码
渲染過程大概是:先找到所有的a
,沿著a
的父元素找出h3
,然後再沿著h3
,找出.nav
。中途找到了符合符合規則的節點就加入結果集。如果找到根元素html
都沒有匹配,則不再遍歷這條路徑,從下一個a
#開始重複這個查找匹配(只要頁面上有多個最右節點為a
)。
Tips:為什麼CSS選擇器是從右向左匹配的?
CSS中更多的選擇器是不會匹配的,所以在考慮效能問題時,需要考慮的是如何在選擇器不匹配時提升效率。從右向左匹配就是為了達成這一目的的,透過這個策略能夠使得CSS選擇器在不匹配的時候更有效率。這樣想來,在配對時多耗費一些效能也能夠想的通了。
效能優化中有一個重要的指標-首次有效繪製(First Meaningful Paint,簡稱FMP)即指頁面的首要內容(primary content)出現在螢幕上的時間。此指標影響使用者看到頁面前所需等待的時間,而 內嵌首屏關鍵CSS(即Critical CSS,可以稱之為首屏關鍵CSS) 能減少這一時間。
很多人喜歡透過link
標籤來引用外部CSS檔案
。但要知道的是,將CSS直接內聯到HTML文件中能讓CSS更快速地下載。而使用外部CSS文件時,需要在HTML文檔下載完成後才知道要引用的CSS文件,然後才下載它們。所以說,內聯CSS能夠讓瀏覽器開始頁面渲染的時間提早,因為在HTML下載完成之後就能渲染了。
但是我們不應該將所有的CSS都內聯在HTML文件中,因為[初始擁塞視窗]存在限制(TCP相關概念,通常是14.6kB,壓縮後大小)
,如果內聯CSS後的檔案超出了這個限制,系統就需要在伺服器和瀏覽器之間進行更多次的往返,這樣並不能提前頁面渲染時間。因此,我們應該當只將渲染首屏內容所需的關鍵CSS內聯到HTML中。
⚠️還有一點要注意的是內聯CSS沒有緩存,每次都會隨HTML的加載而重新下載,但我們將內聯首屏關鍵CSS控制在 14.6kB
以內,它對性能優化還是起到正向作用的。 (凡事有利也有弊)
我們需要知道兩點內容:(具體可以看我之前的文章:這些瀏覽器面試題,看看你能回答幾個?)
CSS
不會阻塞DOM
的解析,但會阻塞DOM
的渲染CSS
會阻塞JS
執行,但不會阻塞JS
檔案的下載由於CSS會阻塞DOM的渲染,所以我們將首屏關鍵CSS內聯後,剩餘的非首屏CSS內容可以使用外部CSS,並且異步加載,防止非首屏CSS內容阻塞頁面的渲染。
CSS非同步載入方式
#第一種方法是動態建立
// 创建link标签 const myCSS = document.createElement( "link" ); myCSS.rel = "stylesheet"; myCSS.href = "mystyles.css"; // 插入到header的最后位置 document.head.insertBefore( myCSS, document.head.childNodes[ document.head.childNodes.length - 1 ].nextSibling );
第二种方法是将link元素的media
属性设置为用户浏览器不匹配的媒体类型(或媒体查询)
对浏览器来说,如果样式表不适用于当前媒体类型,其优先级会被放低,会在不阻塞页面渲染的情况下再进行下载。在首屏文件加载完成之后,将media
的值设为screen
或all
,从而让浏览器开始解析CSS。
<link rel="stylesheet" href="mystyles.css" media="noexist" onload="this.media='all'">
第三种方法是通过rel
属性将link
元素标记为alternate
可选样式表
<link rel="alternate stylesheet" href="mystyles.css" onload="this.rel='stylesheet'">
第四种方法是使用rel=preload
来异步加载CSS
<link rel="preload" href="mystyles.css" as="style" onload="this.rel='stylesheet'">
注意,as
是必须的。忽略as
属性,或者错误的as
属性会使preload
等同于XHR
请求,浏览器不知道加载的是什么内容,因此此类资源加载优先级会非常低。as
的可选值可以参考上述标准文档。
看起来,rel="preload"
的用法和上面两种没什么区别,都是通过更改某些属性,使得浏览器异步加载CSS文件但不解析,直到加载完成并将修改还原,然后开始解析。
但是它们之间其实有一个很重要的不同点,那就是使用preload,比使用不匹配的media
方法能够更早地开始加载CSS。所以尽管这一标准的支持度还不完善,仍建议优先使用该方法。
这应该是最容易想到的一个方法了,通过压缩CSS文件大小来提高页面加载速度。现在的构建工具,如webpack、gulp/grunt、rollup等也都支持CSS压缩功能。压缩后的文件能够明显减小,可以大大降低了浏览器的加载时间。
一般情况下,元素的嵌套层级不能超过3级,过度的嵌套会导致代码变得臃肿,沉余,复杂。导致css文件体积变大,造成性能浪费,影响渲染的速度!而且过于依赖HTML文档结构。这样的css样式,维护起来,极度麻烦,如果以后要修改样式,可能要使用!important
覆盖。尽量保持简单,不要使用嵌套过多过于复杂的选择器。
一般情况下,会存在这两种无用的CSS代码:一种是不同元素或者其他情况下的重复代码,一种是整个页面内没有生效的CSS代码。
对于前者,在编写的代码时候,我们应该尽可能地提取公共类,减少重复。对于后者,在不同开发者进行代码维护的过程中,总会产生不再使用的CSS的代码,当然一个人编写时也有可能出现这一问题。而这些无用的CSS代码不仅会增加浏览器的下载量,还会增加浏览器的解析时间,这对性能来说是很大的消耗。所以我们需要找到并去除这些无用代码。
那么我们如何知道哪些CSS代码是无用代码呢?
谷歌的Chrome浏览器就有这种开箱即用的功能。只需转到查看>开发人员>开发人员工具,并在最近的版本中打开Sources选项卡,然后打开命令菜单。然后,点击Coverage,在Coverage analysis窗口中高亮显示当前页面上未使用的代码。
我们有时候可能会写下面这种代码来消除一些标签的默认样式或统一浏览器对标签渲染的差异化:
*{ margin:0; padding:0; }
这样虽然代码量少,但它的性能可不是最佳的,我们最好还是写对应的标签选择器:
body,dl,dd,h1,h2,h3,h4,h5,h6,p,form,ol,ul{ margin:0; padding:0; }
开发时尽量避免使用通配符选择器
一般来讲一个网站上肯定会有很多个小图标,对于这些小图标,目前的主流的解决方案有三个,cssSprite(雪碧图),字体图标,把图片转成base64。
cssSprite
,只需要请求一次,大大的减少了http请求。缺点就是管理不灵活,如果需要新增一个图标,都需要改合并图片的源文件,图标定位也要规范,不然容易干扰图片之间的定位。8K以下的图片才转换成base64编码。
不建议使用@import
主要有以下两点原因:
使用@import
引入CSS会影响浏览器的并行下载。使用@import
引用的CSS文件只有在引用它的那个css文件被下载、解析之后,浏览器才会知道还有另外一个css需要下载,这时才去下载,然后下载后开始解析、构建render tree等一系列操作。这就导致浏览器无法并行下载所需的样式文件。
多个@impor
t会导致下载顺序紊乱。在IE中,@import
会引发资源文件的下载顺序被打乱,即排列在@import后面的js文件先于@import下载,并且打乱甚至破坏@import自身的并行下载。
在ID选择器前面嵌套其它选择器纯粹是多余的
.content #text
)完全是浪费性能。div#text
或者.box#text
。这两种方式完全是多余的,理由就是ID在页面就是唯一的。前面加任何东西都是多余的!CSS 支持多种单位和数字格式,可以删除尾随和跟随的零,零始终是零,添加维度不会为包含的信息附带任何价值。
.box { padding: .2px; margin: 20px; avalue: 0; }
在网站的使用过程中,某些操作会导致样式的改变,这时浏览器需要检测这些改变并重新渲染,其中有些操作所耗费的性能更多。我们都知道,当FPS为60时,用户使用网站时才会感到流畅。这也就是说,我们需要在16.67ms内完成每次渲染相关的所有操作,所以我们要尽量减少耗费更多的操作。
减少回流与重绘
合并对DOM
样式的修改,采用css class
来修改
const el = document.querySelector('.box') el.style.margin = '5px' el.style.borderRadius = '12px' el.style.boxShadow = '1px 3px 4px #ccc'
建议使用css class
.update{ margin: 5px; border-dadius: 12px; box-shadow: 1px 3px 4px #ccc } const el = document.querySelector('.box') el.classList.add('update')
如果需要对DOM进行多次访问,尽量使用局部变量缓存该DOM
避免使用table布局,可能很⼩的⼀个⼩改动会造成整个table的重新布局
CSS选择符从右往左匹配查找,避免节点层级过多
DOM离线处理,减少回流重绘次数
离线的DOM不属于当前DOM树中的任何一部分,这也就意味着我们对离线DOM处理就不会引起页面的回流与重绘。
display: none
,上面我们说到了 (display: none
) 将元素从渲染树中完全移除,元素既不可见,也不是布局的组成部分,之后在该DOM上的操作不会触发回流与重绘,操作完之后再将display
属性改为显示,只会触发这一次回流与重绘。提醒⏰:visibility : hidden
的元素只对重绘有影响,不影响重排。
dom
文档片段,在它上面批量操作 dom
,操作完成之后,再添加到文档中,这样只会触发一次重排。const el = document.querySelector('.box') const fruits = ['front', 'nanjiu', 'study', 'code']; const fragment = document.createDocumentFragment(); fruits.forEach(item => { const li = document.createElement('li'); li.innerHTML = item; fragment.appendChild(li); }); el.appendChild(fragment);
const el = document.querySelector('.box') const fruits = ['front', 'nanjiu', 'study', 'code']; const cloneEl = el.cloneNode(true) fruits.forEach(item => { const li = document.createElement('li'); li.innerHTML = item; cloneEl.appendChild(li); }); el.parentElement.replaceChild(cloneEl,el)
DOM脱离普通文档流
使用absoult
或fixed
让元素脱离普通文档流,使用绝对定位会使的该元素单独成为渲染树中 body
的一个子元素,重排开销比较小,不会对其它节点造成太多影响。
CSS3硬件加速(GPU加速)
使用css3硬件加速,可以让transform、opacity、filters
这些动画不会引起回流重绘 。但是对于动画的其它属性,比如background-color
这些,还是会引起回流重绘的,不过它还是可以提升这些动画的性能。
常见的触发硬件加速的css属性:
将节点设置为图层
图层能够阻⽌该节点的渲染⾏为影响别的节点。⽐如对于video标签来说,浏览器会⾃动将该节点变为图层。
具体回流与重绘知识点可以看我这篇文章:https://juejin.cn/post/7064077572132323365
(学习视频分享:web前端)
以上是CSS如何進行效能優化?優化小技巧分享的詳細內容。更多資訊請關注PHP中文網其他相關文章!