1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
|
---
title: Предзагрузчик контента - rel="preload"
slug: Web/HTML/Preloading_content
translation_of: Web/HTML/Preloading_content
---
<p class="summary">Значение <code>preload</code> атрибута {{htmlattrxref("rel", "link")}} в элементе {{htmlelement("link")}} позволяет вам запросить данные через {{htmlelement("head")}} вашего HTML, указав необходимые вашей странице ресурсы ещё в начале её жизненного цикла, - до того, как сработает основной механизм отрисовки браузера. Это гарантирует, что предзагрузчик нужных ресурсов с меньшей вероятностью заблокирует отрисовку страницы, тем самым улучшая её производительность.</p>
<p class="summary">В этой статье приведено основное руководство про работе с <code><link rel="preload"></code>.</p>
<h2 id="Основы">Основы</h2>
<p>Чаще всего вы используете простой <code><link></code> элемент, когда загружаете CSS файлы со стилем вашей страницы:</p>
<pre class="brush: html notranslate"><link rel="stylesheet" href="styles/main.css"></pre>
<p>Однако, здесь мы будем использовать значение <code>preload</code> для атрибута <code>rel</code>, которое превратит тег <code><link></code> в предзагрузчик для любого ресурса, который мы пожелаем. Для этого необходимо будет указать:</p>
<ul>
<li>Адрес пути к ресурсу в атрибуте {{htmlattrxref("href", "link")}};</li>
<li>Тип ресурса в атрибуте {{htmlattrxref("as", "link")}}.</li>
</ul>
<p>Простой пример может выглядеть так: (смотрите наш <a href="https://github.com/mdn/html-examples/tree/master/link-rel-preload/js-and-css">JS и CSS пример из источника</a>, и <a href="https://mdn.github.io/html-examples/link-rel-preload/js-and-css/">живой пример</a>):</p>
<pre class="brush: html notranslate"><head>
<meta charset="utf-8">
<title>Пример пред-загрузки JS и CSS</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>прыгающие шарики</h1>
<canvas></canvas>
<script src="main.js"></script>
</body></pre>
<p>Мы сделали предзагрузку наших файлов CSS и JavaScript, чтобы они стали доступны для рендеринга страницы сразу же, как это потребуется. Этот пример отчасти банален, поскольку браузер, вероятнее всего, обнаружит элементы <code><link rel="stylesheet"></code> и <code><script></code> в одном чанке (блоке) с основным HTML, но преимущества более явно проявятся, если далее по странице будут обнаружены более объёмные ресурсы. Это могут быть:</p>
<ul>
<li>Ресурсы, на которые ссылаются стили из CSS (шрифты, изображения);</li>
<li>Ресурсы, затребованные из JavaScript (например JSON, динамически подгружаемые скрипты, воркеры);</li>
<li>Огромных размеров изображения, видео.</li>
</ul>
<p><code>preload</code> имеет и другие преимущества. Использование атрибута <code>as</code> для указания типа содержимого пред-загрузки позволит браузеру:</p>
<ul>
<li>Точнее расставить приоритеты при загрузке ресурсов.</li>
<li>Сохранить в кеше затребованный ресурс для его повторного использования в случае необходимости.</li>
<li>Применять корректную <a href="/ru/docs/Web/HTTP/CSP">политику безопасности содержимого (content security policy)</a> для ресурсов.</li>
<li>Правильно устанавливать заголовки {{HTTPHeader("Accept")}} для выбранного запроса.</li>
</ul>
<h3 id="Какие_типы_контента_могут_быть_предзагружены">Какие типы контента могут быть предзагружены?</h3>
<p>Разного типа контент можно предзагрузить. Вот основные атрибуты значения <code>as</code>:</p>
<ul>
<li><code>audio</code>: Аудио файлы.</li>
<li><code>document</code>: HTML документ для {{htmlelement("frame")}} или {{htmlelement("iframe")}}.</li>
<li><code>embed</code>: Ресурс, встроенный в {{htmlelement("embed")}} элемент.</li>
<li><code>fetch</code>: Ресурс с доступом к запросу выборки или XHR, подобие файлу ArrayBuffer или JSON.</li>
<li><code>font</code>: Шрифты.</li>
<li><code>image</code>: Картинки.</li>
<li><code>object</code>: Ресурс встроенный в {{htmlelement("object")}} элемент.</li>
<li><code>script</code>: JavaScript.</li>
<li><code>style</code>: CSS таблица стилей.</li>
<li><code>track</code>: WebVTT.</li>
<li><code>worker</code>: A JavaScript веб-worker и общий worker.</li>
<li><code>video</code>: Видео.</li>
</ul>
<div class="note">
<p><strong>Примечание</strong>: вы можете прочитать немного больше об этих значениях и веб-функциях, которыми они будут пользоваться, в спецификации Предзагрузка — <a href="https://w3c.github.io/preload/#link-element-extensions">расширения элементов ссылок</a>. Также обратите внимание, что полный список значений атрибут <code>as</code> может принимать в зависимости от определений в спецификации Fetch — <a href="https://fetch.spec.whatwg.org/#concept-request-destination">запрос направления</a>.</p>
</div>
<h2 id="Включение_MIME-типов">Включение MIME-типов</h2>
<p>Элементы <code><link></code> могут принимать атрибут {{htmlattrxref("type", "link")}}, содержащий MIME-тип ресурса целевого элемента. Это особенно полезно при пред-загрузке ресурсов. Браузер использует значение атрибута <code>type</code> и начнёт его загрузку, если поддержка ресурса определена, иначе проигнорирует его.</p>
<p>См. <a href="https://github.com/mdn/html-examples/tree/master/link-rel-preload/video">полный исходный код</a>, (а также <a href="https://mdn.github.io/html-examples/link-rel-preload/video/">пример живой версии видео</a>).</p>
<pre class="brush: html notranslate"><head>
<meta charset="utf-8">
<title>Пример пред-загрузки видео</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> Ваш браузер не поддерживает видео в формате HTML5.
Взамен - <a href="sintel-short.mp4"> ссылка на видео </a>.</p>
</video>
</body></pre>
<p>В этом случае браузеры, поддерживающие MP4, будут пред-загружать и использовать MP4, что, как мы надеемся, сделает видеоплеер плавное/отзывчивее для пользователей. Браузеры, не поддерживающие MP4, могут загружать версию WebM, при этом не получая преимуществ пред-загрузки. Это показывает, как пред-загрузка контента может сочетаться с философией прогрессивного улучшения.</p>
<h2 id="Выборки_из_разных_источников">Выборки из разных источников</h2>
<p>Если настройки CORS ваших сайтов правильные, вы можете успешно пред-загрузить ресурсы разных источников, установив атрибут {{htmlattrxref("crossorigin", "link")}} в элементе <code><link></code>.</p>
<p>Один из интересных случаев, когда это применимо, даже если выборка не из разных источников, - это файлы шрифтов. По разным причинам они должны быть получены с использованием анонимного режима CORS (см. <a href="https://drafts.csswg.org/css-fonts/#font-fetching-requirements">Требования к выборке шрифтов</a>, если вас заинтересуют все подробности).</p>
<p>Используем этот случай в качестве примера, во-первых, загрузка шрифтов - действительно хороший вариант использования пред-загрузки, а во-вторых, - это проще, чем настраивать пример запроса с перекрёстным источником. Полный пример исходного кода <a href="https://github.com/mdn/html-examples/tree/master/link-rel-preload/fonts">есть на GitHub</a> (<a href="https://mdn.github.io/html-examples/link-rel-preload/fonts/">также смотрите его вживую</a>):</p>
<pre class="brush: html notranslate"><head>
<meta charset="utf-8">
<title>Примеры веб-шрифтов</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></pre>
<p>Легко узреть, что мы не только предоставляем подсказки типа MIME в атрибутах типа, но также предоставляем атрибут <code>crossorigin</code> для решения проблемы CORS.</p>
<h2 id="Including_media">Including media</h2>
<p>One nice feature of <code><link></code> elements is their ability to accept {{htmlattrxref("media", "link")}} attributes. These can accept <a href="/en-US/docs/Web/CSS/@media#Media_types">media types</a> or full-blown <a href="/en-US/docs/Web/CSS/Media_Queries/Using_media_queries">media queries</a>, allowing you to do responsive preloading!</p>
<p>Давайте посмотрим на очень простой пример (см. его на GitHub - <a href="https://github.com/mdn/html-examples/tree/master/link-rel-preload/media">исходный код</a> и <a href="https://mdn.github.io/html-examples/link-rel-preload/media/">живой пример</a>):</p>
<pre class="brush: html notranslate"><head>
<meta charset="utf-8">
<title>Пример адаптивной предзагрузки</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>Мой сайт</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></pre>
<p>Вы видите, что мы включаем <code>media</code>-атрибуты в наши элементы <code><link></code> так, чтобы узкое изображение пред-загружалось на устройство пользователя с узким экраном, а более широкое - на устройство с более широким экраном. Чтобы изображение к заголовку было в зависимости от результата - мы используем {{domxref("Window.matchMedia")}} / {{domxref("MediaQueryList")}} (подробности см. в разделе <a href="/en-US/docs/Web/CSS/Media_Queries/Testing_media_queries">Тест медиавыражений</a>).</p>
<p>Это увеличивает вероятность того, что шрифт будет доступен к моменту завершения рендеринга страницы, что сокращает количество проблем с FOUT (вспышка нестилизованного текста).</p>
<p>Обратите внимание, что это не должно ограничиваться изображениями или даже файлами одного типа - думайте масштабно! Возможно, вы могли бы предварительно загрузить, а затем отобразить простую диаграмму SVG, если пользователь находится на узком экране, где пропускная способность и ЦП потенциально более ограничены, или предзагрузить сложный фрагмент JavaScript, а затем использовать его для рендеринга интерактивной 3D-модели, если ресурсы пользователя более многочисленны.</p>
<h2 id="Скрипты_и_предзагрузки">Скрипты и предзагрузки</h2>
<p>Ещё одна полезная вещь в этих предзагрузках, это то, что вы можете выполнять их полностью со скриптами, если необходимо. Например, мы сейчас создаём экземпляр {{domxref("HTMLLinkElement")}}, затем включим её в DOM:</p>
<pre class="brush: js notranslate"><code class="language-javascript"><span class="keyword token">var</span> preloadLink <span class="operator token">=</span> document<span class="punctuation token">.</span><span class="function token">createElement</span><span class="punctuation token">(</span><span class="string token">"link"</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
preloadLink<span class="punctuation token">.</span>href <span class="operator token">=</span> <span class="string token">"myscript.js"</span><span class="punctuation token">;</span>
preloadLink<span class="punctuation token">.</span>rel <span class="operator token">=</span> <span class="string token">"preload"</span><span class="punctuation token">;</span>
preloadLink<span class="punctuation token">.</span><span class="keyword token">as</span> <span class="operator token">=</span> <span class="string token">"script"</span><span class="punctuation token">;</span>
document<span class="punctuation token">.</span>head<span class="punctuation token">.</span><span class="function token">appendChild</span><span class="punctuation token">(</span>preloadLink<span class="punctuation token">)</span><span class="punctuation token">;</span>
</code></pre>
<p>Подразумевается, что браузер загрузит JavaScript файл, но, пока не будет его применять.</p>
<p>Чтобы выполнить его, вы можете использовать следующую конструкцию:</p>
<pre class="brush: js notranslate"><code class="language-javascript"><span class="keyword token">var</span> preloadedScript <span class="operator token">=</span> document<span class="punctuation token">.</span><span class="function token">createElement</span><span class="punctuation token">(</span><span class="string token">"script"</span><span class="punctuation token">)</span><span class="punctuation token">;</span>
preloadedScript<span class="punctuation token">.</span>src <span class="operator token">=</span> <span class="string token">"myscript.js"</span><span class="punctuation token">;</span>
document<span class="punctuation token">.</span>body<span class="punctuation token">.</span><span class="function token">appendChild</span><span class="punctuation token">(</span>preloadedScript<span class="punctuation token">)</span><span class="punctuation token">;</span>
</code></pre>
<p>Это полезно, когда вы хотите загрузить скрипт в кеш, но применять его только тогда, когда это необходимо.</p>
<h2 id="Другие_механизмы_предзагрузки_ресурсов">Другие механизмы предзагрузки ресурсов</h2>
<p>Существуют и другие функции предварительной загрузки, но ни одна из них не подходит так, как <code><link rel="preload"></code>:</p>
<ul>
<li><code><link rel="prefetch"></code> давно поддерживается в браузерах, но предназначен для предварительной загрузки ресурсов, которые будут использоваться при следующей навигации/загрузке страницы (например, когда вы переходите на следующую страницу). Это нормально, но бесполезно для текущей страницы! Кроме того, браузеры будут отдавать ресурсам предварительной загрузки более низкий приоритет, чем ресурсам <code>предзагрузки</code> - текущая страница важнее следующей. См. <a href="/en-US/docs/Web/HTTP/Link_prefetching_FAQ">Предвыборку ссылок FAQ</a> для подробностей.</li>
<li><code><link rel = "subresource"></code> некоторое время назад поддерживался в Chrome и предназначался для решения проблемы предзагрузки ресурсов для текущей навигации/загрузки страницы, но у него была проблема - не было возможности определить приоритет для получения элементов. (<code>as</code> тогда не существовало), поэтому все они в конечном итоге были извлечены с довольно низким приоритетом, что не помогло ситуации.</li>
<li>Существует ряд загрузчиков ресурсов на основе сценариев, но они не имеют никакой власти над очередью приоритетов выборки браузера и подвержены тем же проблемам с производительностью.</li>
</ul>
<h2 id="Specifications" name="Specifications">Характеристики</h2>
<table class="standard-table">
<thead>
<tr>
<th scope="col">Specification</th>
<th scope="col">Status</th>
<th scope="col">Comment</th>
</tr>
</thead>
<tbody>
<tr>
<td>{{SpecName('Preload','#x2.link-type-preload','preload')}}</td>
<td>{{Spec2('Preload')}}</td>
<td>Further details of <code>preload</code>.</td>
</tr>
<tr>
<td>{{SpecName('HTML WHATWG', 'link-type-preload', 'rel=preload')}}</td>
<td>{{Spec2('HTML WHATWG')}}</td>
<td>Definition of <code>rel=preload</code>.</td>
</tr>
</tbody>
</table>
<h2 id="Совместимость_с_браузером">Совместимость с браузером</h2>
<p class="hidden">Таблица совместимости на этой странице создана на основе структурированных данных. Если вы хотите внести свой вклад в данные, пожалуйста, проверьте <a href="https://github.com/mdn/browser-compat-data">https://github.com/mdn/browser-compat-data</a> и отправьте нам запрос на перенос.</p>
<p>{{Compat("html.elements.link.rel.preload")}}</p>
<h2 id="Смотрите_также">Смотрите также</h2>
<ul>
<li><a href="https://www.smashingmagazine.com/2016/02/preload-what-is-it-good-for/">Preload: What Is It Good For?</a> by Yoav Weiss</li>
</ul>
<p>{{QuickLinksWithSubpages("/en-US/docs/Web/HTML")}}</p>
|