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