Самый простой способ асинхронной загрузки CSS

От автора: одной из наиболее эффективных вещей, которые мы можем сделать для повышения производительности и устойчивости страниц, является загрузка CSS способом, который не задерживает рендеринг страниц.

Это связано с тем, что по умолчанию браузеры загружают внешний CSS-файл синхронно — блокируя весь рендеринг страницы, пока CSS-файл загружается и анализируется — и то, и другое вызывает потенциальные задержки. Конечно, по крайней мере часть CSS сайта должна быть загружена до того, как странице будет разрешено начать рендеринг, и для немедленного получения этого начального CSS в браузер, мы рекомендуем встраивание (или HTTP2 сервер-пушинг) CSS. Для сайтов с небольшим общим объемом этого может быть достаточно, но если размер CSS велик (скажем, больше 15–20 КБ), это может улучшить производительность. После разделения менее критичный CSS должен быть загружен в фоновом режиме — то есть асинхронно. В этой статье я постараюсь описать наш предпочтительный способ сделать это, на самом деле он существует уже много лет.

Есть несколько способов асинхронной загрузки CSS, но ни один из них не настолько интуитивен, как вы могли бы ожидать. В отличие от элементов script, для CSS нет атрибутов async или defer, которые можно просто применить к элементу link, поэтому в течение многих лет мы поддерживали проект loadCSS, чтобы немного упростить процесс загрузки асинхронного CSS. Однако в последнее время браузеры стандартизировали свое поведение при загрузке CSS, поэтому специальный скрипт, такой как loadCSS, вероятно, больше не нужен.

Код

Сегодня, обладая небольшим знанием того, как браузер обрабатывает различные атрибуты элементов link, мы можем добиться эффекта асинхронной загрузки CSS с помощью короткой строки HTML. Вот самый простой способ асинхронной загрузки таблицы стилей:

<link rel="stylesheet" href="/path/to/my.css" media="print" onload="this.media='all'">

Более детально

Эта строка HTML лаконична, но не очень интуитивна, поэтому давайте разберем, что здесь происходит.

Для начала для атрибута media элемента link установлено значение print. print — это type медиа, который указывает «применять правила этой таблицы стилей для печатных носителей», или, другими словами, применять их, когда пользователь пытается распечатать страницу. Следует признать, что мы хотим, чтобы наша таблица стилей применялась ко всем медиа (особенно к экранам), а не только к печати, но, объявив тип медиа, который не соответствует текущей среде, мы можем получить интересный и полезный эффект: браузер загрузит таблицу стилей без задержки рендеринга страницы, асинхронно! Это полезно, но это не все, чего мы хотим. Мы также хотим, чтобы CSS действительно применялся к экранной среде после его загрузки. Для этого мы можем использовать атрибут onload, чтобы установить для media — all по окончании загрузки.

Не можете ли rel = preload сделать то же самое?

Да, аналогично! В последние год или два мы использовали link[rel=preload] (вместо rel=stylesheet), чтобы получить аналогичный шаблон, как указано выше (переключение атрибута rel после загрузки, вместо атрибута media соответственно). Это все еще хорошо работает, однако есть несколько недостатков, которые следует учитывать при использовании preload. Во-первых, поддержка браузерами все еще недостаточна, поэтому необходимо использовать полифилл (такой, как предоставляет loadCSS), если вы хотите полагаться на него для извлечения и применения таблицы стилей в разных браузерах. Что еще более важно, preload выборка файлов происходит очень рано, с наивысшим приоритетом, потенциально лишая приоритета другие важные загрузки, и они могут иметь более высокий приоритет, чем вам на самом деле нужно для некритического CSS.

К счастью, если вам нужна высокоприоритетная выборка, которую дает rel=preload (в браузерах, которые ее поддерживают), вы можете объединить ее с приведенным выше шаблоном, например так:

<link rel="preload" href="/path/to/my.css" as="style">
<link rel="stylesheet" href="/path/to/my.css" media="print" onload="this.media='all'">

Учитывая простую и декларативную природу приведенного выше кода, мы бы выбрали его вместо полифилла, поэтому подход с переключением медиа print снова является предпочтительным.

Почему бы не использовать вымышленный атрибут media?

Любой, кто следил за нашими работами в течение последних нескольких лет, может вспомнить, что мы использовали значения атрибутов media, такие как «only x», для достижения того же эффекта, что дает «print», предоставляя значение, которое не соответствует ни одной среде, так как x — это бессмысленный тип медиа. Когда браузеры обнаруживают несоответствующие типы медиа, они в настоящее время обрабатывают их одинаково — загружают файл в любом случае. Тем не менее, некоторые команды браузеров начинают рассматривать различие между несоответствующими типами медиа и недопустимыми, теми которые (или вообще не распознаются браузером), и, возможно, не запрашивают файлы, которые связаны с использованием недопустимых типов медиа. Это сломало бы множество существующих реализаций загрузки CSS, так что это маловероятно, но в целях безопасности мы рекомендуем использовать допустимый, но не соответствующий тип, например print.

Вам может не понадобиться loadCSS…

Мы продолжаем поддерживать loadCSS и считаем его полезным в некоторых ситуациях, в частности , для извлечения программно файла CSS с JavaScript, например: loadCSS(«/path/to/my.css»). Если вы уже используете loadCSS или его шаблон полифилл rel=preload, вам не нужно ничего менять. Внутри он использует ту же механику, которая описана в этой статье.

Тем не менее, мы находим, что простой HTML-подход может быть всем, что вам нужно. И часто он просто работает лучше всего. Спасибо за прочтение!

Автор: Scott Jehl

Источник: https://www.filamentgroup.com

Редакция: Команда webformyself.