?
本文檔使用 php中文網手冊 發(fā)布
<link>
元素的 rel
屬性的屬性值preload
能夠讓你在你的HTML頁面中 <head>
元素內部書寫一些聲明式的資源獲取請求,可以指明哪些資源是在頁面加載完成后即刻需要的。對于這種即刻需要的資源,你可能希望在頁面加載的生命周期的早期階段就開始獲取,在瀏覽器的主渲染機制介入前就進行預加載。這一機制使得資源可以更早的得到加載并可用,且更不易阻塞頁面的初步渲染,進而提升性能。本文提供了一個如何有效使用preload
機制的基本說明。
<link>
標簽最常見的應用情形就是被用來加載CSS文件,進而裝飾你的頁面:
<link rel="stylesheet" href="styles/main.css">
但是在這里,我們將使用preload
作為rel
屬性的屬性值。這種做法將把<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"></script></body>
在這里,我們預加載了CSS和JavaScript文件,所以在隨后的頁面渲染中,一旦需要使用它們,它們就會立即可用。這個例子本身可能有些平淡,但預加載的好處可以更清晰直觀的得到展示,在隨后的渲染過程中,這些資源得到有效使用。對于更大的文件來說,也是如此。 例如那些在CSS文件中指向的資源,比如字體或是圖片;再比如更大的圖片和視頻文件。
preload
還有許多其他好處。使用 as
來指定將要預加載的內容的類型,將使得瀏覽器能夠:
更精確地優(yōu)化資源加載優(yōu)先級。
匹配未來的加載需求,在適當的情況下,重復利用同一資源。
為資源應用正確的內容安全策略。
為資源設置正確的 Accept
請求頭。
許多不同類型的內容都可以被預加載,一些主要可用的as
屬性值列舉如下:
audio
: 音頻文件。
document
: 一個將要被嵌入到<frame>
或<iframe>
內部的HTML文檔。
embed
: 一個將要被嵌入到<embed>
元素內部的資源。
fetch
: 那些將要通過fetch和XHR請求來獲取的資源,比如一個ArrayBuffer或JSON文件。
font
: 字體文件。
image
: 圖片文件。
object
: 一個將會被嵌入到<embed>
元素內的文件。
script
: JavaScript文件。
style
: 樣式表。
track
: WebVTT文件。
worker
: 一個JavaScript的web worker或shared worker。
video
: 視頻文件。
注意: 你可以通過進一步閱讀link element extensions來了解關于這些屬性值以及其他在Preload方案中預期將采納的特性的細節(jié)。同樣需要注意的是,關于as
屬性的有效值得完整列表是由Fetch方案來制定的,可以查看request destinations來進行了解。
<link>
元素可以接受一個type
屬性。這一屬性可以包含該元素所指向資源的MIME類型。在瀏覽器進行預加載的時候,這個屬性值將會非常有用——瀏覽器將使用type
屬性來判斷它是否支持這一資源,如果瀏覽器支持這一類型資源的預加載,下載將會開始,否則便對其加以忽略。
你可以在我們的視頻示例中看到一個與此有關的示例:
<head> <meta charset="utf-8"> <title>Video preload example</title> <link rel="preload" href="sintel-short.mp4" as="video" type="video/mp4"> </head> <body> <video controls> <source src="sintel-short.mp4" type="video/mp4"> <source src="sintel-short.webm" type="video/webm"> <p>Your browser doesn't support HTML5 video. Here is a <a href="sintel-short.mp4">link to the video</a> instead.</p> </video> </body>
在這個實例中,支持MP4格式的瀏覽器將僅預加載并使用MP4資源,以使得視頻播放器的表現盡可能的流暢,或者說,為用戶提供更好的響應。而不支持MP4格式的瀏覽器仍然能夠加載視頻的WebM版本,但無法體驗到與加載帶來的良好體驗。這個例子展示了預加載機制如何與漸進式增強的哲學進行有機的結合。
如果你已經有了一個可以正確工作的CORS設置,那么你也可以同樣成功的預加載那些跨域資源,只需要你在<link>
元素中設置好crossorigin
屬性即可。
一個有趣的情況是,如果你需要獲取的是字體文件,那么即是是非跨域的情況下,也需要應用這一屬性。因為各種各樣的原因,這些這些獲取請求必須使用以匿名模式使用CORS(如果你對其中的細節(jié)感興趣,可以查看Font fetching requirements一文)。
我們將以這個情況作為一個示例——首先是由于字體文件的加載是預加載方面一個好的用例,其次,這也比真正的配置一個跨域請求的例子要簡單許多。你可以查看 在Github上的示例源代碼:
<head> <meta charset="utf-8"> <title>Web font example</title> <link rel="preload" href="fonts/cicle_fina-webfont.eot" as="font" type="application/vnd.ms-fontobject" crossorigin="anonymous"> <link rel="preload" href="fonts/cicle_fina-webfont.woff2" as="font" type="font/woff2" crossorigin="anonymous"> <link rel="preload" href="fonts/cicle_fina-webfont.woff" as="font" type="font/woff" crossorigin="anonymous"> <link rel="preload" href="fonts/cicle_fina-webfont.ttf" as="font" type="font/ttf" crossorigin="anonymous"> <link rel="preload" href="fonts/cicle_fina-webfont.svg" as="font" type="image/svg+xml" crossorigin="anonymous"> <link rel="preload" href="fonts/zantroke-webfont.eot" as="font" type="application/vnd.ms-fontobject" crossorigin="anonymous"> <link rel="preload" href="fonts/zantroke-webfont.woff2" as="font" type="font/woff2" crossorigin="anonymous"> <link rel="preload" href="fonts/zantroke-webfont.woff" as="font" type="font/woff" crossorigin="anonymous"> <link rel="preload" href="fonts/zantroke-webfont.ttf" as="font" type="font/ttf" crossorigin="anonymous"> <link rel="preload" href="fonts/zantroke-webfont.svg" as="font" type="image/svg+xml" crossorigin="anonymous"> <link href="style.css" rel="stylesheet" type="text/css"></head><body> ...</body>
你可以看到,在這里,我們不僅通過配置type
屬性提供了一個MIME類型的暗示,我們也提供了一個crossorigin
屬性來處理CORS問題。
<link>
元素有一個很棒的特性是它們能夠接受一個media
屬性。它們可以接受媒體類型或有效的媒體查詢作為屬性值,這將令你能夠使用響應式的預加載!
讓我們來看一個簡單的示例:
<head> <meta charset="utf-8"> <title>Responsive preload example</title> <link rel="preload" href="bg-image-narrow.png" as="image" media="(max-width: 600px)"> <link rel="preload" href="bg-image-wide.png" as="image" media="(min-width: 601px)"> <link rel="stylesheet" href="main.css"></head><body> <header> <h1>My site</h1> </header> <script> var mediaQueryList = window.matchMedia("(max-width: 600px)"); var 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
屬性,因此,當用戶在使用較窄屏幕的設備時,較窄的圖片將會被預加載,而在較寬的設備上,較寬的圖片將被預加載。然后我們仍需要在header元素上附加合適的圖片——通過Window.matchMedia
/MediaQueryList
來加以實現(可以查看Testing media queries一文來了解更多信息)。
這一特性將使另一種情況成為可能——字體在隨著頁面渲染完成的時候即可使用,減少了FOUT (無樣式字體閃爍,flash of unstyled text)問題。
值得注意的是,這一特特性并不僅限于圖片,或其他有著同樣類型的文件,還有更多想象空間。比如,你可以在用戶僅有較窄的屏幕,CPU和帶寬資源較為有限的情況下預加載并展示一個簡單的SVG圖表,而在用戶資源較為充裕的時候再去加載一系列復雜的JavaScript文件以顯示一個有交互功能的3D模型。
另一項很棒的關于預加載的事情是,如果需要,你可以完全以腳本化的方式來執(zhí)行這些預加載操作。例如,我們在這里創(chuàng)建一個HTMLLinkElement
實例,然后將他們附加到DOM上:
var preloadLink = document.createElement("link");preloadLink.href = "myscript.js";preloadLink.rel = "preload";preloadLink.as = "script";document.head.appendChild(preloadLink);
這意味著瀏覽器將預加載這個JavaScript文件,但并不實際執(zhí)行它。
如果要對其加以執(zhí)行,在需要的時候,你可以執(zhí)行:
var preloadedScript = document.createElement("script");preloadedScript.src = "myscript.js";document.body.appendChild(preloadedScript);
當你需要預加載一個腳本,但需要推遲到需要的時候才令其執(zhí)行時,這種方式會特別有用。
還存在一些其他預加載機制,但沒有哪個會比<link rel="preload">
在大多數情況下更符合你的需要和預期:
<link rel="prefetch">
已經被許多瀏覽器支持了相當長的時間,但它是意圖預獲取一些資源,以備下一個導航/頁面使用(比如,當你去到下一個頁面時)。這很好,但對當前的頁面并沒有什么助益。此外,瀏覽器會給使用prefetch
的資源一個相對較低的優(yōu)先級——與使用preload
的資源相比。畢竟,當前的頁面比下一個頁面相對更加重要。查看Link prefetching FAQ可以了解更多細節(jié)。
<link rel="subresource">
被Chrome支持了有一段時間,并且已經有些搔到預加載當前導航/頁面(所含有的資源)的癢處了。但它有一個問題——沒有辦法處理所獲取內容的優(yōu)先級(as
也并不存在),所以最終,這些資源會以一個相當低的優(yōu)先級被加載,這使得它能提供的幫助相當有限。
除以上這些意外,還有大量的基于腳本的資源加載器。但這些加載器對于瀏覽器的加載優(yōu)先級隊列完全束手無策,這也使得他們不得不屈服于同樣的性能問題。
規(guī)范 | 狀態(tài) | 評論 |
---|---|---|
預加載該規(guī)范中“預加載”的定義。 | 工作草案 | 預加載的更多細節(jié)。 |
HTML生活標準該規(guī)范中'<link>'的定義。 | 生活水平 | 預加載的基本定義。 |
Feature | Chrome | Firefox (Gecko) | Internet Explorer | Opera | Safari |
---|---|---|---|---|---|
Basic support | 50.0 | 56 (56)1 | No support | 47 | 11 |
Feature | Android | Android Webview | Firefox Mobile (Gecko) | IE Mobile | Opera Mobile | Safari Mobile | Chrome for Android |
---|---|---|---|---|---|---|---|
Basic support | 56 | 50.0 | 56.0 (56)1 | No support | (Yes) | 11 | 50.0 |