iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 2
3
Modern Web

前端開發 30 個問題系列 第 2

關於 <link> 的兩三事

前言
2020 秋天,我將用 30 天的時間,來嘗試回答和網路前端開發相關的 30 個問題。30 天無法一網打盡浩瀚的前端知識,有些問題可能對有些讀者來說相對簡單,不過期待這趟旅程,能幫助自己、也幫助讀者打開不同的知識大門。有興趣的話,跟著我一起探索吧!

<link href='...'> 而不是 <link src='...'>

昨天講完 HTML 文件中最上面的 DOCTYPE,如果稍微往下看一點,通常就會看到我們引入 stylesheet 的地方:

<link rel="stylesheet" href="./style.css">

但看到這裡就有另外一個疑問:同樣是引入外部資源,為什麼在 link element 裡面使用的是 href,而在 script element 或是 img element 裡面用的是 src 呢?為什麼不能像下面這樣使用呢?

<link rel="stylesheet" src="./style.css">

Answer

其實我們可以從 MDN 或是 W3C 的文件當中看到,link element 當中只有 href 這個屬性,沒有 src 的屬性。因此,如果想要透過 src 來引入資源,其實是無效的喔。

感謝大家收看,鐵人賽第二天順利下莊!

image

等等,這樣好像太懶惰了,讓我們多花一點時間看看不同的東西吧

href vs. src

首先,讓我們來看看 hrefsrc 使用上的差別,這裡我就以常見的

<link rel="stylesheet" href="./style.css">

<script src="script.js"></script>

來做個比較。

實際上我並沒有在文件上找到「定義上」的差別,所以只能從「實務面」回頭推敲當初設計的原則。如果我們回頭查看 W3C 的文件,會看到關於 link 與 href 的介紹:

The link element allows authors to link their document to other resources. The address of the link(s) is given by the href attribute...

以及 script 與 src 的介紹:

The script element allows authors to include dynamic script and data blocks in their documents. The element does not represent content for the user.
...
Classic scripts and module scripts can be embedded inline, or be imported from an external file using the src attribute, which if specified gives the URL of the external script resource to use. ..

我想兩邊最大的差異在於, link/href 是將這份文件與其他資源「建立連結或關係」;而 script/src 則是「引入資源」。所以用白話文解釋剛剛兩段程式碼,就會是

<!-- 請參考 style.css 文件來渲染畫面 -->
<link rel="stylesheet" href="./style.css">

<!-- 請載入 script.js 並在此執行 -->
<script src="script.js"></script>

如果舉其他例子來看看,就像是

<!-- 若使用者點擊,請帶他到這個網站去(不是載入這個網站當中的資源)-->
<a href="http://www.td.coffee/">link</a>
<!-- 請載入 photo.jpg 這個資源 -->
<img src="./photo.jpg">

看到這裡,我們知道了 hrefsrc 在使用上的差別,接下來,我們來看一下 <link> 可以被放在哪裡。

can be placed everywhere!

一般來說,我們會將 <link rel="stylesheet" href="./style.css"> 放在 <head> 當中,所以當瀏覽器開始讀取 HTML 文件的時候,就會在最一開始讀取拿來參考的 CSS 文件。

不過實際上我發現,其實可以把 <link ...> 放在任何地方。真的是「任何地方」。不管是 <body> 的裡面外面,甚至是 html 的裡面或外面都行!

如果有兩個 <link ...> 又會怎麼影響呢?這裡我做了一個小實驗,在內容的前後各加上一個 <link ...>

<body>
  <link rel="stylesheet" href="style1.css">
  <p>Hello world!</p>
  <link rel="stylesheet" href="style2.css">
</body>

其中 style1.css 與 style2.css 的內容分別為

// style1.css
p {
  color: blue; 
}
// style2.css
p {
  color: red; 
}

不意外,最後畫面渲染出來的結果,文字會是紅色的,瀏覽器會讀取兩份檔案,後面讀取到的 style2.css 會覆蓋前面 style1.css 的設定。

這裡可能又會延伸出另外問題是,究竟文字會先被渲染成藍色、再變成紅色,或者是直接渲染出來就是紅色了呢?

根據 MDN Preload scanner 的解釋:

While the browser builds the DOM tree, this process occupies the main thread. As this happens, the preload scanner will parse through the content available and request high priority resources like CSS, JavaScript, and web fonts. Thanks to the preload scanner, we don't have to wait until the parser finds a reference to an external resource to request it. It will retrieve resources in the background so that by the time the main HTML parser reaches requested assets, they may possibly already be in flight, or have been downloaded. The optimizations the preload scanner provides reduce blockages.

<link rel="stylesheet" src="styles.css"/>
<script src="myscript.js" async></script>
<img src="myimage.jpg" alt="image description"/>
<script src="anotherscript.js" async></script>

瀏覽器會預先掃描文件上所有的 <link rel="stylesheet" ...>,所以剛剛的例子,會是瀏覽器讀取完兩份 stylesheet 之後,再渲染出最後紅色的文字。


另外,我還做了個實驗是,在最一開始的 HTML 文件中只放入 style1.css。接著,我透過 DOM 與 setTimeout 的方式,在 N 秒之後才把 <link rel="stylesheet" href="style2.css"> 放進 HTML 文件當中,同時我也在 style2.css 加上 transition: color 1s 1s linear; 的效果,就會發現畫面重新被渲染的過程。

最後,其實 <srcipt ...> 也是可以放在 HTML 文件當中的任何地方,只不過關於載入的細節,我想留到後面的主題再深入講解。

Ending

有時候看似理所當然的東西,一但深入追究,就會不知其所以然,不過這也是學習有趣的地方。我們明天見啦!

Ref:


TD
Be curious as astronomer, think as physicist, hack as engineer,
fight as baseball player
More about me

"Life is like riding a bicycle. To keep your balance, you must keep moving."


上一篇
What is DOCTYPE?
下一篇
What is metadata?
系列文
前端開發 30 個問題31

尚未有邦友留言

立即登入留言