rel=preload
Baseline 廣泛可用 *
<link> 元素的 rel 屬性的 preload 值允許你在 HTML 的 <head> 中宣告抓取請求,指定頁面很快將需要的資源。你希望在頁面生命週期早期開始載入這些資源,趕在瀏覽器主要渲染機制啟動之前。這確保它們能更早可用,並且不太可能阻塞頁面渲染,從而提高效能。儘管名稱中包含“載入”一詞,但它並不會載入並執行指令碼,而只是以更高的優先順序安排其下載和快取。
基本原理
你最常使用 <link> 來載入 CSS 檔案以美化頁面
<link rel="stylesheet" href="styles/main.css" />
然而,這裡我們將使用 rel 值為 preload,它將 <link> 轉換為我們想要的任何資源的預載入器。你還需要指定
- 資源在
href屬性中的路徑。 - 資源在
as屬性中的型別。
一個例子可能看起來像這樣(參見我們的 JS 和 CSS 示例原始碼,以及即時示例)
<head>
<meta charset="utf-8" />
<title>JS and CSS preload example</title>
<link rel="preload" href="style.css" as="style" />
<link rel="preload" href="main.js" as="script" />
<link rel="stylesheet" href="style.css" />
</head>
<body>
<h1>bouncing balls</h1>
<canvas></canvas>
<script src="main.js" defer></script>
</body>
這裡我們預載入了 CSS 和 JavaScript 檔案,以便它們在頁面後續渲染需要時立即可用。這個例子很簡單,因為瀏覽器可能在與預載入相同的 HTML 塊中發現了 <link rel="stylesheet"> 和 <script> 元素,但當資源發現得越晚且越大時,其優勢會更加明顯。例如
- CSS 內部指向的資源,如字型或影像。
- JavaScript 可以請求的資源,如匯入的指令碼。
preload 還有其他優點。使用 as 來指定要預載入的內容型別,允許瀏覽器
哪些型別的內容可以預載入?
許多內容型別都可以預載入。可能的 as 屬性值有
fetch:透過 fetch 或 XHR 請求訪問的資源,如 ArrayBuffer、WebAssembly 二進位制檔案或 JSON 檔案。font:字型檔案。image:影像檔案。script:JavaScript 檔案。style:CSS 樣式表。track:WebVTT 檔案。
注意: font 和 fetch 預載入需要設定 crossorigin 屬性;請參閱下面的啟用 CORS 的抓取請求。
注意: HTML 規範中對這些值以及它們預期被哪些 Web 功能消費有更詳細的描述——請參閱 Link type "preload"。另請注意,as 屬性可接受的完整值列表受 Fetch 規範管理——請參閱 request destinations。
包含 MIME 型別
<link> 元素可以接受一個 type 屬性,其中包含元素指向的資源的 MIME 型別。這在預載入資源時特別有用——瀏覽器將使用 type 屬性值來判斷它是否支援該資源,如果支援則下載,否則忽略。
<head>
<meta charset="utf-8" />
<title>Image preload example</title>
<link rel="preload" href="flower.avif" as="image" type="image/avif" />
</head>
<body>
<picture>
<source src="flower.avif" type="image/avif" />
<source src="flower.webp" type="image/webp" />
<img src="flower.jpg" />
</picture>
</body>
上面示例中的程式碼導致 image/avif 影像僅在支援的瀏覽器中預載入——對於瀏覽器支援 image/avif 的使用者,導致 image/avif 影像實際被使用(因為它是第一個指定的 <source>)。這使得對於瀏覽器支援 image/avif 的使用者來說,影像下載量有望更小。
請注意,對於瀏覽器同時支援 image/avif 和 image/webp 的使用者,如果在該程式碼中也指定了 <link rel="preload" href="flower.webp" as="image" type="image/webp"> 元素,那麼 image/avif 和 image/webp 影像都將被預載入——即使最終只會使用其中一個。
因此,不鼓勵為同一資源的多種型別指定預載入。相反,最佳實踐是僅為大多數使用者可能實際使用的型別指定預載入。這就是為什麼上面示例中的程式碼沒有為 image/webp 影像指定預載入。
然而,缺乏預載入並不能阻止 image/webp 影像被需要它的使用者實際使用:對於瀏覽器不支援 image/avif 但支援 image/webp 的使用者,上面示例中的程式碼仍然會導致 image/webp 影像被使用——但它這樣做,而不會對大多數其他使用者造成不必要的預載入。
啟用 CORS 的抓取請求
當預載入啟用 CORS 的資源(例如,fetch()、XMLHttpRequest 或字型)時,需要特別注意在你的 <link> 元素上設定 crossorigin 屬性。該屬性需要設定為與資源的 CORS 和憑證模式匹配,即使抓取不是跨域的。
如上所述,一個有趣的適用情況是字型檔案。由於各種原因,這些必須使用匿名模式 CORS 獲取(參見 字型獲取要求)。
讓我們以這個案例為例。你可以在 GitHub 上檢視完整的 示例原始碼(也可以即時檢視)
<head>
<meta charset="utf-8" />
<title>Web font example</title>
<link
rel="preload"
href="fonts/cicle_fina-webfont.woff2"
as="font"
type="font/woff2"
crossorigin />
<link
rel="preload"
href="fonts/zantroke-webfont.woff2"
as="font"
type="font/woff2"
crossorigin />
<link href="style.css" rel="stylesheet" />
</head>
<body>
…
</body>
我們不僅在 type 屬性中提供了 MIME 型別提示,還提供了 crossorigin 屬性,以確保預載入的 CORS 模式與最終的字型資源請求匹配。
包含媒體
<link> 元素的一個很好的特性是它們能夠接受 media 屬性。這些屬性可以接受媒體型別或完整的媒體查詢,允許你進行響應式預載入!
讓我們看一個例子(在 GitHub 上檢視——原始碼,即時示例)
<head>
<meta charset="utf-8" />
<title>Responsive preload example</title>
<link
rel="preload"
href="bg-image-narrow.png"
as="image"
media="(width <= 600px)" />
<link
rel="preload"
href="bg-image-wide.png"
as="image"
media="(width > 600px)" />
<link rel="stylesheet" href="main.css" />
</head>
<body>
<header>
<h1>My site</h1>
</header>
<script>
const mediaQueryList = window.matchMedia("(width <= 600px)");
const header = document.querySelector("header");
if (mediaQueryList.matches) {
header.style.backgroundImage = 'url("bg-image-narrow.png")';
} else {
header.style.backgroundImage = 'url("bg-image-wide.png")';
}
</script>
</body>
我們在 <link> 元素上包含了 media 屬性,這樣如果使用者視口較窄,則預載入窄影像;如果使用者視口較寬,則載入寬影像。我們使用 Window.matchMedia / MediaQueryList 來實現這一點(有關更多資訊,請參閱 測試媒體查詢)。
這種技術也適用於其他資源型別。例如,與字型一起使用時,預載入使得字型在渲染時更有可能可用,從而減少了無樣式文字閃爍 (FOUT) 的可能性。
這不必侷限於影像,甚至不必侷限於相同型別的檔案——著眼大局!如果使用者處於頻寬和 CPU 可能更有限的窄螢幕上,你或許可以預載入並顯示簡化的 SVG 圖表,或者如果使用者資源更充足,則預載入複雜的 JavaScript 片段,然後使用它來渲染互動式 3D 模型。
指令碼和預載入
注意: 如果你正在使用 JavaScript 模組,請改用 <link rel="modulepreload">。
這些預載入的另一個優點是你可以用指令碼執行它們。例如,這裡我們建立一個 HTMLLinkElement 例項,然後將其附加到 DOM
const preloadLink = document.createElement("link");
preloadLink.href = "myscript.js";
preloadLink.rel = "preload";
preloadLink.as = "script";
document.head.appendChild(preloadLink);
這意味著瀏覽器將預載入 myscript.js 檔案,但實際上尚未將其投入使用。要使用它,你可以這樣做
const preloadedScript = document.createElement("script");
preloadedScript.src = "myscript.js";
document.body.appendChild(preloadedScript);
當你想要預載入一個指令碼,但將執行推遲到你需要它的確切時間時,這很有用。
規範
| 規範 |
|---|
| HTML # 連結型別預載入 |
瀏覽器相容性
載入中…
另見
- 推測性載入 用於比較
<link rel="preload">和其他類似效能改進功能。 - 預載入:它有什麼用? 作者:Yoav Weiss