link和@import的區別


由link和@import的區別引發的CSS渲染雜談

 

我們都知道,外部引入 CSS 有2種方式,link標簽和@import
它們有何本質區別,有何使用建議,在考察外部引入 CSS 這部分內容時,經常被提起。

如今,很多學者本着知其然不欲知其所以然的學習態度,不求甚解,只求結論。
所以,本文遵循 css hack 的漸進識別原則,
結論 → 區別 → 爭議 → 細節 → 祖墳 → 感想,逐漸加深理論層級,
力爭每個 level 的讀者,都能 get 到自己想要的內容,不必繼續閱讀下去。

結論

就結論而言,強烈建議使用link標簽,慎用@import方式。
這樣可以避免考慮@import的語法規則和注意事項,避免產生資源文件下載順序混亂和http請求過多的煩惱。

區別

1.從屬關系區別
@import是 CSS 提供的語法規則,只有導入樣式表的作用;link是HTML提供的標簽,不僅可以加載 CSS 文件,還可以定義 RSS、rel 連接屬性等。

2.加載順序區別
加載頁面時,link標簽引入的 CSS 被同時加載;@import引入的 CSS 將在頁面加載完畢后被加載。

3.兼容性區別
@import是 CSS2.1 才有的語法,故只可在 IE5+ 才能識別;link標簽作為 HTML 元素,不存在兼容性問題。

4.DOM可控性區別
可以通過 JS 操作 DOM ,插入link標簽來改變樣式;由於 DOM 方法是基於文檔的,無法使用@import的方式插入樣式。

5.權重區別(該項有爭議,下文將詳解)
link引入的樣式權重大於@import引入的樣式。

爭議

不知從什么時候開始,當你在網上搜索link@import的區別時,千篇一律的答案里就悄悄的多了一句“link引入的樣式權重大於@import引入的樣式”。
但是並沒有一份答案,附帶着對這句話的任何解釋或實例。

這句話究竟是什么意思,該怎么理解呢?

發揚探索精神,我們不妨繼續查閱資料。后來發現,還是有不少文章和帖子,對這句話表示質疑,進而自己寫了 demo 去驗證,驗證的結果,確實無法與這句話相吻合。
而且,筆者也並未發現能清楚、正確、有理有據的解釋這個結論到底對,還是不對的文章。

那么這個結論,最初是從哪里來的,可能已經無從考證了。

換個思維方式,不去爭辯它的對錯了,探索未果,我們就從這個結論的核心關鍵詞“權重”出發,去研究它。

說到“權重”,有必要再解釋一下:CSS 中的權重,指的是選擇器的優先級。

CSS 選擇器的權重高,即選擇器的優先級高。
CSS 的優先級特性表現為,對同一 HTML 元素設置樣式時,不同選擇器的優先級不同,優先級低的樣式將被高優先級的樣式層疊掉。

CSS 權重優先級順序簡單表示為:
!important > 行內樣式 > ID > 類、偽類、屬性 > 標簽名 > 繼承 > 通配符

為了便於理解權重的計算方式,我們按以下方式進行數值假設分析:

選擇器 權重
通配符 0
標簽 1
類/偽類/屬性 10
ID 100
行內樣式 1000
important 1/0(無窮大)

再舉實例:

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <style type="text/css"> #myid { /* id選擇器權重為100 */ background-color: pink; } #divid .myspan input { /* 權重為 100 + 10 + 1 = 111 */ background-color: yellow; } input[type="button"] { /* 權重為 10 */ color: white !important; /* !important權重為無窮大 */ } input.myclass { /* 此為標簽指定式選擇器,權重為 1 + 10 = 11 */ color: black; } </style> </head> <body> <div id="divid"> <span class="myspan"> <input type="button" id="myid" class="myclass" name="myname"  value="點我" style=" color: green;"> <!-- style樣式的權重為1000 --> </span> </div> </body> </html>

每個樣式的權重值,都在實例中,以注釋的形式標明。
根據權重值可知,最終,這個按鈕的樣式一定是,藍色背景,白色字,結果如下圖:

存在!important時,不作他想,一定是權重最大的樣式。

既然我們了解了,CSS 中的權重是怎么回事,那回到主題,“link引入的樣式權重大於@import引入的樣式”,
難道 CSS 的引入方式也有權重嗎?其實我們不必糾結它是否有權重之說,我們只需理論結合實際的去分析,各種情況下,結果如何即可。
現有如下3個css文件:

/* green.css */ div { background-color: green; border: 3px solid red; } /* yellow.css */ div { background-color: yellow; border: 3px solid black; } /* blue.css */ @import url("green.css"); div{ background-color: blue; }

實例1:

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <!-- 實例1. link標簽引入yellow.css,內聯樣式引入green.css --> <link rel="stylesheet" href="yellow.css"> <style type="text/css"> @import url("green.css"); </style> </head> <body> <div style="width: 50px; height: 50px;"></div> <!-- 盒子為,綠色背景,紅色邊框,即green.css生效 --> </body> </html>

實例1結果如下圖:

實例2:

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <!-- 實例2. 內聯樣式引入green.css,link標簽引入yellow.css --> <style type="text/css"> @import url("green.css"); </style> <link rel="stylesheet" href="yellow.css"> </head> <body> <div style="width: 50px; height: 50px;"></div> <!-- 盒子為黃色背景,黑色邊框,即yellow.css生效 --> </body> </html>

實例2結果如下圖:

對比實例1和實例2這兩個正好相反的結果可知,link@import並沒有產生類似權重的效果,只是單純的體現了CSS的層疊性,寫在后面的樣式,覆蓋前面的樣式。

實例3:

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <!-- 實例3. 內聯樣式引入green.css,內聯樣式中設置粉色背景 --> <style type="text/css"> @import url("green.css"); div { background-color: pink; } </style> </head> <body> <div style="width: 50px; height: 50px;"></div> <!-- 盒子為粉色背景,紅色邊框,即green.css已生效,但背景色被內聯樣式層疊為粉色 --> </body> </html>

實例3結果如下圖:

實例4:

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <!-- 實例4. link標簽引入blue.css,blue.css中引入green.css --> <link rel="stylesheet" href="blue.css"> </head> <body> <div style="width: 50px; height: 50px;"></div> <!-- 盒子為藍色背景,紅色邊框,即green.css已生效,但背景色被blue.css層疊為藍色 --> </body> </html>

實例4結果如下圖:

分析實例3和實例4的結果可知:

對於實例3,我們看到紅色邊框,證明內聯樣式中使用@import引入的green.css已經生效,但其背景樣式被內聯樣式中的粉色背景層疊掉,這個現象表明,@import不只是如我們看到的那樣,處於內聯樣式頂部,其被引入的樣式,在結構上,也確實是被置於內聯樣式之前,所以內聯樣式才能夠層疊掉它。

同理,實例4中,在link標簽引入的blue.css文件內,頂部同樣存在@import引入的green.css,紅色邊框依然可以證明,green.css已經生效,但其背景樣式被blue.css本身的藍色背景層疊掉,@import引入的樣式在blue.css中也是被置於它本身樣式之前的。

到此為止,我展開了大膽的猜想,“link引入的樣式權重大於@import引入的樣式”,這個結論的給出者,是想告訴大家:

link標簽引入的 CSS 文件中,使用@import時需注意,如果已經存在相同樣式,@import引入的這個樣式將被該 CSS 文件本身的樣式層疊掉,表現出link標簽引入的樣式權重大於@import引入的樣式這樣的直觀效果。

對於我設想的結論,似乎挺能說通的,畢竟這是實踐出的結果。

那些驗證過此結論的前人,他們都是在一個 HTML 頁面中,一前一后分別使用link和內聯樣式的@import去比較的,我在實例1和實例2中也是如此做的,並不能反推出“link引入的樣式權重大於@import引入的樣式”這個結論,所以,我不自量力的認為,這個結論其實最初只是丟了個已知條件而已。

那么我們一起把這個結論重新梳理一下:在link標簽引入的 CSS 文件中使用@import時,相同樣式將被該 CSS 文件本身的樣式層疊。

Ps.首先感謝各種看官的閱讀。筆者屬於學習階段,學識尚淺,雖然本文結論已得到筆者編碼驗證,但不排除筆者大腦短路、措辭有誤的可能,有緣閱讀到此處的都是真愛,希望諸位大拿、大牛、大仙、大聖、大神們不吝賜教,及時指正,避免誘導萌新誤入歧途,再次向你們表達筆者的謝意!

細節

既然已經說了這么多,就順便提一下關於@import使用時的其它細節。

在《CSS權威指南》中寫道:

@import一定要寫在除@charset外的其他任何 CSS 規則之前,如果置於其它位置將會被瀏覽器忽略,而且,在@import之后如果存在其它樣式,則@import之后的分號是必須書寫,不可省略的。

到此為止,似乎事情都弄清楚了,但是突然又有個疑點浮現出來:

在討論區別的時候,不是說加載頁面時,link標簽引入的 CSS 先於@import引入的 CSS 加載嗎,那link標簽引入的樣式又怎會把@import引入的樣式層疊掉呢?

要回答這個問題,首先我們要一起明確一些有關瀏覽器的概念:

瀏覽器執行過程可以簡單分為加載、解析、渲染,這三個步驟。

加載:根據請求的URL進行域名解析,向服務器發送請求,接收響應文件(如 HTML、JS、CSS、圖片等)。

解析:對加載到的資源(HTML、JS、CSS等)進行語法解析,構建相應的內部數據結構(比如HTML的DOM樹,JS對象的屬性表,CSS的樣式規則等)。

渲染:構建渲染樹,對各個元素進行位置計算、樣式計算等,然后根據渲染樹完成頁面布局及繪制的過程(可以理解為“畫”頁面元素)。

這幾個過程不是完全孤立的,會有交叉,比如HTML加載后就會進行解析,然后拉取HTML中指定的CSS、JS等。`

現在,我們應該已經了解了加載和渲染的概念,明白它們是兩個不同的過程,那么對上文中拋出的疑問繼續追問:

link先於@import加載,是不是也先於@import渲染呢?

實際上,渲染的動作一般都會執行多次,最后一次渲染,一定是依據之前加載過的所有樣式整合后的渲染樹進行繪制頁面的,已經被渲染過的頁面元素,也會被重新渲染。

那么我們就可以把@import這種導入 CSS 文件的方式理解成一種替換,CSS 解析引擎在對一個 CSS 文件進行解析時,如在文件頂部遇到@import,將被替換為該@import導入的 CSS 文件中的全部樣式。

峰回路轉,柳暗花明,終於弄明白為何@import引入的樣式,會被層疊掉了。其雖然后被加載,卻會在加載完畢后置於樣式表頂部,最終渲染時自然會被下面的同名樣式層疊。

至此為止,“link引入的樣式權重大於@import引入的樣式”這個結論,我終於為它圓了場。但願此結論的作者,本意真如我的猜測,否則若是我多心而跑偏了的話,不敢想象這背后究竟隱藏着多大的秘密。

祖墳

有些細心而專業的讀者可能已經發現了,我用自己的思路和措辭,粗略的解釋了有關 CSS 加載和渲染的知識,有些涉世未深的前端愛好者可能會一頭霧水,無法作為系統學習的依據。這不打緊,出來混,祖墳總是要刨的,想要透徹的學習相關內容,進一步了解底層原理的學者,我早已為你備下了豐厚的見面禮~

有關link@import在性能分析方面的比較,國外的高手早在多年前就曾執過筆:

愛好母語的請戳我https://www.stevesouders.com/blog/2009/04/09/dont-use-import/
閱讀英語的請戳我https://www.qianduan.net/high-performance-web-site-do-not-use-import/

有關瀏覽器內部工作原理的神作,也是幾年前出自歪果仁大牛:

1 為普通話https://kb.cnblogs.com/page/129756/
2 for Englishhttp://taligarsiel.com/Projects/howbrowserswork1.htm

對知識有所渴望的你,趕快點擊上面的傳送門,相信你一定會有豐富的收獲。

感想

我喜歡讀別人探究類的技術文章,不只是可以學習技術上的知識,更是可以學習別人探索的精神和思考問題的邏輯。或許已經有過不少前人如我一樣,對本文的爭議結論,有所質疑,前思后想過一番,得出了自己的見解,只是沒有成文,或者沒有發表而已。

那么其他人呢,就只是單純的復制結論或記憶結論么。

其實我覺得,在咱們這個領域,不求甚解可以,人雲亦雲不行。一句含有信息量的句子,進入大腦時,總得自己考慮考慮吧,不要讓我們的大腦充當轉發器,最不濟,也得是個解析器吧。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM