本篇來源


這一篇是 High Performance Web Sites 的作者 Steve Souders 在 2009 年寫的一篇部落格, 我在 2014 年時研究網站效能時找到的. 原本只記下 URL, 但是隔年回頭查閱時發現圖片都不見了, 幾經辛苦查找, 終於找到有圖片的轉載, 於是複製了圖片, 並把原部落格的整份文章也複製下來作為備份 (原備份貼文時間戳記是 2015-10-08 12:06:56)

今日得空, 便重新整理翻譯, 也分享給大家. 本篇雖然有點久遠 (09~21 有 12 年之久了). 但所陳述的大部份依然是正確無誤. 現下 MS IE (至 IE11) 已經沒了後續的更新, 彼時 MS 要大家都改用 Win10 和 Edge. 現在更是連後繼的 MS Edge 也放棄了原有的核心轉向使用 Chromium 核心了.

原文出處 https://www.stevesouders.com/blog/2009/04/09/dont-use-import/


don't use @import

April 9, 2009 12:32 am

In Chapter 5 of High Performance Web Sites, I briefly mention that @import has a negative impact on web page performance. I dug into this deeper for my talk at Web 2.0 Expo, creating several test pages and HTTP waterfall charts, all shown below. The bottomline is: use LINK instead of @import if you want stylesheets to download in parallel resulting in a faster page.

勿用 @import


在 "高性能網站建設指南"(註一) 這本書的第五章裡, 我簡要的提到了 @import 對於網站的性能有負面的影響. 後來為了 Web 2.0 Expo 的演講, 我對這個議題進行了更深入的研究, 並建了一些測試頁面以及 HTTP 瀑布圖(註二), 如下面的文章所展示. 最重要的是: 請使用 LINK 來替代 @import, 如果你想要利用平行下載樣式檔來使你的網頁更快.

註一: 大陸的譯本書名

註二: 當時的 browser 並沒有內建 debugger. 彼時 IE 用的是 host script debugger.

LINK vs. @import

There are two ways to include a stylesheet in your web page. You can use the LINK tag:

<link rel='stylesheet' href='a.css'>

Or you can use the @import rule:

<style>
@import url('a.css');
</style>

I prefer using LINK for simplicity—you have to remember to put @import at the top of the style block or else it won't work. It turns out that avoiding @import is better for performance, too.

LINK 對比 @import


有兩種方法可以在網頁中引入樣式文件. 你可以使用 LINK 標籤:

<link rel='stylesheet' href='a.css'>

或者你也可以使用 @import 規則:

<style>
@import url('a.css');
</style>

我傾向使用 LINK 因為簡單 — (相對於) 你必須記得將 @import 放到樣式區塊的最前面, 否則它是不會有作用的. (出乎意料的) 結果是, 避免使用 @import 同時也使得網站性能更好.

@import @import

I'm going to walk through the different ways LINK and @import can be used. In these examples, there are two stylesheets: a.css and b.css. Each stylesheet is configured to take two seconds to download to make it easier to see the performance impact. The first example uses @import to pull in these two stylesheets. In this example, called @import @import, the HTML document contains the following style block:

<style>
@import url('a.css');
@import url('b.css');
</style>

If you always use @import in this way, there are no performance problems, although we'll see below it could result in JavaScript errors due to race conditions. The two stylesheets are downloaded in parallel, as shown in Figure 1. (The first tiny request is the HTML document.) The problems arise when @import is embedded in other stylesheets or is used in combination with LINK.

Figure 1

Figure 1. always using @import is okay

@import @import


以下我將探索各種不同運用 LINK@import 的方式. 在這些例子中, 有兩個樣式文件: a.cssb.css. 每一個樣式文件都被調整成需要花兩秒鐘來下載, 以便 (它們對) 網站性能的影響比較容易被查覺. 第一個例子使用 @import 來引入這二個樣式文件. 此例我們以 @import @import 來稱呼它, 它的 HTML 文件包含了如下的樣式區塊:

<style>
@import url('a.css');
@import url('b.css');
</style>

如果你一直都是以這種方式來使用 @import, 那不會有性能問題, 儘管之後我們會看到它可能會引發 JavaScript 錯誤, 因為競態條件 (race condition) 的因素. 如圖1所示, 兩個樣式文件是同時平行下載 (第一個小的請求是 HTML 文件本身). 問題會出現在當 @import 被嵌套在其它樣式文件裡或是和 LINK 一起使用的時候.

Figure 1

全部都只用 @import 是可以的

LINK @import

The LINK @import example uses LINK for a.css, and @import for b.css:

<link rel='stylesheet' type='text/css' href='a.css'>
<style>
@import url('b.css');
</style>

In IE (tested on 6, 7, and 8), this causes the stylesheets to be downloaded sequentially, as shown in Figure 2. Downloading resources in parallel is key to a faster page. As shown here, this behavior in IE causes the page to take a longer time to finish.

Figure 2. link mixed with @import breaks parallel downloads in IE

Figure 2. link mixed with @import breaks parallel downloads in IE

LINK @import


例子 LINK @importLINK 引入 a.css, 然後用 @import 來引入 b.css:

<link rel='stylesheet' type='text/css' href='a.css'>
<style>
@import url('b.css');
</style>

使用 IE 時 (以 IE6, IE7 和 IE8 測試過), 這樣寫導致樣式文件依序被下載下來, 如圖2所示. 平行下載資源檔案是加速網頁的關鍵所在. 如圖所示, 使用 IE 時這個行為 (寫法) 導致頁面需要更多的時間才能完成.(註三)

Figure 2. link mixed with @import breaks parallel downloads in IE

使用 IE 時 LINK@import 混用會破壞平行下載

註三: 其他 browser 並不會.

LINK with @import

In the LINK with @import example, a.css is inserted using LINK, and a.css has an @import rule to pull in b.css:

in the HTML document:
<link rel='stylesheet' type='text/css' href='a.css'>
in a.css:
@import url('b.css');

This pattern also prevents the stylesheets from loading in parallel, but this time it happens on all browsers. When we stop and think about it, we shouldn't be too surprised. The browser has to download a.css and parse it. At that point, the browser sees the @import rule and starts to fetch b.css.

Figure 3. using @import from within a LINKed stylesheet breaks parallel downloads in all browsers

Figure 3. using @import from within a LINKed stylesheet breaks parallel downloads in all browsers

LINK with @import


LINK with @import 例子中, a.css 是用 LINK 插入到頁面中, 然後在 a.css 裡利用 @import 規則來引入 b.css.

HTML 文件內容:

<link rel='stylesheet' type='text/css' href='a.css'>

a.css 文件內容:

@import url('b.css');

這種模式同樣也會阻斷平行下載, 不過這次是所有的瀏覽器都這樣. 其實只要稍微細想一下, 我們應該不會太驚呀. 瀏覽器必須先下載並解析它 (a.css). 這時瀏覽器才會知道 (a.css 內容裡) 有 @import 規則, 然後才開始下載 b.css.

Figure 3. using @import from within a LINKed stylesheet breaks parallel downloads in all browsers

LINK 樣式文件裡使用 @import 會使所有的瀏覽器都無法平行下載

LINK blocks @import

A slight variation on the previous example with surprising results in IE: LINK is used for a.css and for a new stylesheet called proxy.css. proxy.css is configured to return immediately; it contains an @import rule for b.css.

in the HTML document:
<link rel='stylesheet' type='text/css' href='a.css'>
<link rel='stylesheet' type='text/css' href='proxy.css'>
in proxy.css:
@import url('b.css');

The results of this example in IE, LINK blocks @import, are shown in Figure 4. The first request is the HTML document. The second request is a.css (two seconds). The third (tiny) request is proxy.css. The fourth request is b.css (two seconds). Surprisingly, IE won't start downloading b.css until a.css finishes. In all other browsers, this blocking issue doesn't occur, resulting in a faster page as shown in Figure 5.

Figure 4. LINK blocks @import embedded in other stylesheets in IE

Figure 4. LINK blocks @import embedded in other stylesheets in IE

Figure 5. LINK doesnt block @import embedded stylesheets in browsers other than IE

Figure 5. LINK doesn't block @import embedded stylesheets in browsers other than IE

LINK 阻斷 @import


這個例子和上例只差一點點, 使用 IE 時卻有另人震驚的結果: 使用 LINK 引入 a.css 和另一個新的樣式文件 proxy.css. proxy.css 被設定成立刻返回, 內容只是使用 @import 規則來引入 b.css.

HTML 文件內容:

<link rel='stylesheet' type='text/css' href='a.css'>
<link rel='stylesheet' type='text/css' href='proxy.css'>

proxy.css 文件內容:

@import url('b.css');

這個例子以 IE 瀏覽的結果 (LINK 阻斷 @import) 如圖4所示. 第一個請求是 HTML 檔. 第二個請求是 a.css (兩秒鐘), 第三個 (很小的那個) 的請求是 proxy.css. 第四個請求是 b.css (兩秒鐘). 令人震驚的是, IE 在 a.css 下載完成之前不會開始下載 b.css. 但是其它的瀏覽器並不會發生這種情況, 結果是頁面顯示比較快, 如圖5所示.

Figure 4. LINK blocks @import embedded in other stylesheets in IE

LINK 阻斷了平行下載嵌入在其他樣式文件中的 @import, 使用 IE 時.

Figure 5. LINK doesnt block @import embedded stylesheets in browsers other than IE

LINK 並不會阻斷平行下載以 @import 嵌入的樣式文件, 使用非 IE 瀏覽器.

many @imports

The many @imports example shows that using @import in IE causes resources to be downloaded in a different order than specified. This example has six stylesheets (each takes two seconds to download) followed by a script (a four second download).

<style>
@import url('a.css');
@import url('b.css');
@import url('c.css');
@import url('d.css');
@import url('e.css');
@import url('f.css');
</style>
<script src='one.js' type='text/javascript'></script>

Looking at Figure 6, the longest bar is the four second script. Even though it was listed last, it gets downloaded first in IE. If the script contains code that depends on the styles applied from the stylesheets (a la getElementsByClassName, etc.), then unexpected results may occur because the script is loaded before the stylesheets, despite the developer listing it last.

Figure 6. @import causes resources to be downloaded out-of-order in IE

Figure 6. @import causes resources to be downloaded out-of-order in IE

many @imports


這個 many @imports 的例子顯示了使用 IE 時會使資源檔案沒有以指定的順序下載. 此例中, 有 6 個樣式表 (每個的下載時間都是兩秒) 後面跟著一個 JS 腳本 (下載需時四秒).

<style>
@import url('a.css');
@import url('b.css');
@import url('c.css');
@import url('d.css');
@import url('e.css');
@import url('f.css');
</style>
<script src='one.js' type='text/javascript'></script>

圖6中最長的長條是需時四秒下載的腳本. 儘管它是被列在最後面, 但是 IE 依然先下載它. 如果腳本中的程式相依於套用來自樣式文件中的樣式 (例如 getElementsByClassName 等等), 那就可能因為腳本的下載先於樣式而發生非預期結果, 即便開發人員已經把它放在最後面.

Figure 6. @import causes resources to be downloaded out-of-order in IE

@import 在 IE 中引發了資源下載順序被打亂.

LINK LINK

It's simpler and safer to use LINK to pull in stylesheets:

<link rel='stylesheet' type='text/css' href='a.css'>
<link rel='stylesheet' type='text/css' href='b.css'>

Using LINK ensures that stylesheets will be downloaded in parallel across all browsers. The LINK LINK example demonstrates this, as shown in Figure 7. Using LINK also guarantees resources are downloaded in the order specified by the developer.

Figure 7. using link ensures parallel downloads across all browsers

Figure 7. using link ensures parallel downloads across all browsers

These issues need to be addressed in IE. It's especially bad that resources can end up getting downloaded in a different order. All browsers should implement a small lookahead when downloading stylesheets to extract any @import rules and start those downloads immediately. Until browsers make these changes, I recommend avoiding @import and instead using LINK for inserting stylesheets.

LINK LINK


使用 LINK 來引入樣式文件更加簡單和安全:

<link rel='stylesheet' type='text/css' href='a.css'>
<link rel='stylesheet' type='text/css' href='b.css'>

使用 LINK 可確保樣式文件在所有瀏覽器都是平行下載的. LINK LINK 的例子展示了這一點, 如圖7所示. 使用 LINK 同樣也保證了資源檔案是依照開發人員指定的順序下載.

Figure 7. using link ensures parallel downloads across all browsers

使用 LINK 確保在所有的瀏覽器裡都是平行下載的.

使用 IE 時, 這些問題都需要解決. 特別糟糕是資源檔案竟然未被依序下載. 所有瀏覽器都應該實作一個往前檢查的機制, 在下載樣式文件時, 檢查並提取出所有的 @import 規則並立即下載這些樣式文件. 在所有的瀏覽器都支援這個功能之前, 我建議避免使用 @import 並以 LINK 來替代.

Update: April 10, 2009 1:07 PM

Based on questions from the comments, I added two more tests: LINK with @imports and Many LINKs. Each of these insert four stylesheets into the HTML document. LINK with @imports uses LINK to load proxy.css; proxy.css then uses @import to load the four stylesheets. Many LINKs has four LINK tags in the HTML document to pull in the four stylesheets (my recommended approach). The HTTP waterfall charts are shown in Figure 8 and Figure 9.

Figure 8. LINK with @imports

Figure 8. LINK with @imports

Figure 9. Many LINKs

Figure 9. Many LINKs

Looking at LINK with @imports, the first problem is that the four stylesheets don't start downloading until after proxy.css returns. This happens in all browsers. On the other hand, Many LINKs starts downloading the stylesheets immediately.

The second problem is that IE changes the download order. I added a 10 second script (the really long bar) at the very bottom of the page. In all other browsers, the @import stylesheets (from proxy.css) get downloaded first, and the script is last, exactly the order specified. In IE, however, the script gets inserted before the @import stylesheets, as shown by LINK with @imports in Figure 8. This causes the stylesheets to take longer to download since the long script is using up one of only two connections available in IE 6&7. Since IE won't render anything in the page until all stylesheets are downloaded, using @import in this way causes the page to be blank for 12 seconds. Using LINK instead of @import preserves the load order, as shown by Many LINKs in Figure 9. Thus, the page renders in 4 seconds.

The load times of these resources are exaggerated to make it easy to see what's happening. But for people with slow connections, especially those in some of the world's emerging markets, these response times may not be that far from reality. The takeaways are:

  • Using @import within a stylesheet adds one more roundtrip to the overall download time of the page.
  • Using @import in IE causes the download order to be altered. This may cause stylesheets to take longer to download, which hinders progress rendering making the page feel slower.

更新: 2009/04/10 下午 1:07


根據讀者的反饋, 我增加了兩項測試: LINK with @importsMany LINKs, 二例都在 HTML 文件中插入了 4 個樣式文件. LINK with @imports 使用 LINK 來引入 proxy.css, 然後 proxy.css 使用 @import 來引入 4 個樣式文件. Many LINKs 則是在 HTML 文件中用了 4 個 LINK 標籤來引入 4 個樣式文件 (我推薦使用的方法). 它們的 HTTP 瀑布圖如圖8圖9所示:

Figure 8. LINK with @imports

LINK with @imports

Figure 9. Many LINKs

Many LINKs

看一下 LINK with @imports, 第一個問題是這 4 個樣式文件在 proxy.css 下載完成之前不會開始下載. 所有的瀏覽器都是如此. 另一方面, Many LINKs 則立即下載這些樣式文件.

第二個問題是 IE 改變下載的順序. 我在頁面的最底部添加了一個 10 秒的腳本 (圖中最長的長條). 使用所有的非 IE 瀏覽器時, @import 的樣式文件 (由 proxy.css 引入) 會先進行下載, 然後才是腳本文件, 依照指定的順序. 然而, 使用 IE 瀏覽器時, 腳本卻先於 @import 樣式被插入, 正如例子 LINK with @imports圖8所示. 這導致了需要花費更多的時間來下載樣式文件, 因為長腳本佔用了 IE6 和 IE7 僅有的兩個可用連接之一. 由於 IE 在樣式文件未完成下載之前, 不會開始渲染頁面中的任何內容, 這種使用 @import 的方式會使頁面保持空白長達 12 秒. 使用 LINK 替代 @import 可以保持載入的順序, 如 Many LINKs圖9所示. 如此, 頁面只需 4 秒即可開始渲染.

下載這些資源的時間被誇大好讓我們可以簡單的查覺到發生了什麼事情. 但對於那些使用慢速連線的用戶來說, 特別是那些新興市場的, 這樣的響應時間可能離實際不遠. 重點是:

  • 在樣式文件中使用 @import 會為頁面整體的下載時間多增加一個往返.
  • 使用 IE 時, @import 會改變文件的下載順序. 這會使樣式文件需要花費更長的時間下載, 進而阻擋了頁面的渲染, 讓人感到頁面比較慢.

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 MagicJackTing 的頭像
    MagicJackTing

    傑克! 真是太神奇了!

    MagicJackTing 發表在 痞客邦 留言(0) 人氣()