Статьи

Борьба с блокировкой рендеринга CSS для быстрого рендеринга сайта

Борьба с блокировкой рендеринга CSS для быстрого рендеринга сайта

Эта статья является частью серии, созданной в сотрудничестве с SiteGround . Спасибо за поддержку партнеров, которые делают возможным использование SitePoint.

Я всегда думал, что решать, как и когда загружать файлы CSS, лучше всего оставить браузерам. Они обрабатывают такие вещи по замыслу. Зачем разработчикам делать что-то большее, чем шлепать элемент ссылки с rel="stylesheet" и href="style.css" внутри раздела <head> документа и забыть об этом?

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

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

Проблема: CSS блокирует рендеринг

Если вы когда-либо использовали Google Page Speed ​​Insights для проверки производительности веб-сайта, вы могли встретить сообщение, подобное этому:

Сообщение от Google Page Speed ​​Insights о блокировке рендера CSS.

Здесь Google Page Insights излагает проблему и предлагает стратегию противодействия ей.

Давайте сначала попробуем немного лучше понять проблему.

Браузеры используют DOM (объектную модель документа) и CSSOM (объектную модель CSS) для отображения веб-страниц. DOM — это модель HTML, необходимая браузеру для отображения структуры и содержимого веб-страницы. CSSOM — это карта CSS, которую браузер использует для стилизации веб-страницы.

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

Проблема заключается в этой задержке, во время которой пользователи могут смотреть на пустой экран в течение нескольких миллисекунд. Не лучший опыт при первой посадке на сайте.

Концепция Критического CSS

Хотя HTML необходим для рендеринга страниц, иначе не было бы ничего для рендеринга, можем ли мы сказать то же самое о CSS?

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

Эта мысль стоит за доминирующим подходом, доступным сегодня для решения этой проблемы, включая предложение, содержащееся в сообщении от Google Page Insights, о котором сообщалось выше. Немного интереса там читает:

Попробуйте отложить или асинхронно загрузить блокирующие ресурсы или вставить критические части этих ресурсов непосредственно в HTML.

Но как вы откладываете или асинхронно загружаете таблицы стилей на свой сайт?

Не так просто, как может показаться. Вы не можете просто выбросить async атрибут в элементе ссылки, как если бы он был <script> <script> тег.

Ниже приведены несколько способов решения этой проблемы разработчиками.

Воспользуйтесь преимуществами типов медиа и медиазапросов, чтобы минимизировать блокировку рендеринга

Илья Григорик иллюстрирует простой способ минимизации блока рендеринга страницы, который включает в себя два этапа:

  • Разделите содержимое вашего внешнего CSS на разные файлы в соответствии с типом мультимедиа и медиазапросами, тем самым избегая больших документов CSS, которые загружаются дольше
  • Ссылка на каждый файл с соответствующим типом медиа и медиа-запрос внутри элемента ссылки. Это предотвращает блокировку рендеринга некоторых файлов таблиц стилей, если не выполняются условия, заданные типом носителя или медиазапросом.

Например, ссылки на ваши внешние CSS-файлы в разделе <head> вашего документа могут выглядеть примерно так:

 <link href="style.css" rel="stylesheet"> <link href="print.css" rel="stylesheet" media="print"> <link href="other.css" rel="stylesheet" media="(min-width: 40em)"> 

Первая ссылка во фрагменте выше не использует какой-либо тип медиа или медиа-запрос. Браузер считает, что это соответствует всем случаям, поэтому он всегда задерживает рендеринг страницы при получении и обработке ресурса.

Вторая ссылка имеет атрибут media="print" , который говорит браузеру: «Привет, браузер, убедитесь, что вы применяете эту таблицу стилей, только если страница печатается». В контексте простого просмотра страницы на экране браузер знает, что таблица стилей не нужна, поэтому он не будет блокировать рендеринг страницы для ее загрузки.

Наконец, третья ссылка содержит media="(min-width: 40em)" , что означает, что media="(min-width: 40em)" стилей, на которую ссылается ссылка, блокирует рендеринг, только если условия, указанные в медиазапросе, совпадают, т. media="(min-width: 40em)" области просмотра равна минимум 40ем. Во всех остальных случаях ресурс не блокирует рендеринг.

Также обратите внимание, что браузер всегда будет загружать все таблицы стилей, но будет отдавать более низкий приоритет неблокирующим.

Подводя итог, этот подход не полностью устраняет проблему, но может значительно минимизировать время, которое браузеры блокируют рендеринг страницы.

Использование директивы предварительной нагрузки для элемента Link

Передовая функция, которую вы можете использовать для противодействия блоку веб-страниц браузерами при получении внешних таблиц стилей, — это стандартная директива preload .

preload — это то, как мы, как разработчики, можем сказать браузерам, чтобы они выбирали определенные ресурсы, потому что мы знаем, что страница скоро понадобится этим ресурсам.

Скотт Джел, дизайнер и разработчик, работающий в The Filament Group, может быть признан первым, кто возился с этой идеей .

Вот что вам нужно сделать.

Добавьте preload к ссылке, ссылающейся на таблицу стилей, добавьте немного JavaScript-магии, используя событие onload ссылки, и в результате вы получите асинхронную загрузку таблицы стилей непосредственно в вашей разметке:

 <link rel="preload" as="style" href="style.css" onload="this.rel='stylesheet'"> 

Приведенный выше фрагмент style.css позволяет браузеру style.css неблокирующим способом. После того, как ресурс завершил загрузку, т.е. произошло событие onload ссылки, скрипт заменяет значение preload rel stylesheet и стили применяются к странице.

В настоящее время поддержка preload в браузере ограничивается Chrome и Opera. Но не бойтесь, под рукой находится полифилл, предоставленный Группой накаливания.

Подробнее об этом в следующем разделе.

Решение Filament Group: от встраивания CSS в сервер HTTP / 2 Push

Решение проблемы отложенного отображения страниц из-за извлечения критических ресурсов долгое время было высшим приоритетом для Filament Group , отмеченного наградами агентства по дизайну и разработке, базирующегося в Бостоне:

Нашим высшим приоритетом в процессе доставки является предоставление HTML, который готов начать рендеринг сразу по прибытии в браузер.

Последнее обновление по оптимизации доставки веб-страниц обрисовывает в общих чертах их прогресс от встраивания критического CSS до сверхэффективного HTTP / 2 Server Push.

Общая стратегия выглядит следующим образом:

  1. Любые ресурсы, которые имеют решающее значение для отображения первого экрана нашей страницы, должны быть включены в HTML-ответ сервера.
  2. Любые активы, которые не являются критичными для этого первого рендеринга, должны доставляться неблокирующим асинхронным способом.

До HTTP / 2 Server Push реализация # 1 состояла в выборе критических правил CSS, т. Е. Тех, которые необходимы для стилей по умолчанию и для плавного рендеринга вышеуказанной части сгиба веб-страницы, и помещения их в элемент <style> внутри <head> раздел страницы. Разработчики Filament Group разработали Critical , классный плагин JavaScript, для автоматизации задачи извлечения критического CSS.

С недавним принятием HTTP / 2 Server Push, Filament Group вышла за рамки встроенного критического CSS.

Что такое сервер Push? Для чего это?

Серверная пересылка позволяет отправлять ресурсы сайта пользователям, даже если они их даже не просили.

Серверная рассылка позволяет серверу превентивно «проталкивать» ресурсы веб-сайта клиенту без явного запроса пользователя об этом. При использовании с осторожностью мы можем отправлять то, что, как мы знаем, понадобится пользователю для запрашиваемой страницы.

Джереми Вагнер

Другими словами, когда браузер запрашивает определенную страницу, скажем, index.html , все ресурсы, от которых зависит страница, будут включены в ответ, например style.css , main.js и т. Д., С огромным ускорением оптимизации на странице скорость рендеринга.

Внедрение на практике # 2 асинхронной загрузки некритического CSS выполняется с использованием комбинации техники директив preload , описанной в предыдущем разделе, и LoadCSS , библиотеки JavaScript Filament Group, которая включает в себя полифилл для тех браузеров, которые не поддерживают preload .

Использование LoadCSS включает добавление этого фрагмента в раздел <head> вашего документа:

 <link rel="preload" href="mystylesheet.css" as="style" onload="this.rel='stylesheet'"> <!-- for browsers without JavaScript enabled --> <noscript><link rel="stylesheet" href="mystylesheet.css"> </noscript> 

Обратите внимание на блок <noscript> который, как обычно, ссылается на файл таблицы стилей, чтобы удовлетворить те ситуации, когда JavaScript работает неправильно или был отключен.

Под <noscript> включите LoadCSS и скрипт полизаполнения LoadCSS rel = preload внутри <script> :

 <script> /*! loadCSS. [c]2017 Filament Group, Inc. MIT License */ (function(){ ... }()); /*! loadCSS rel=preload polyfill. [c]2017 Filament Group, Inc. MIT License */ (function(){ ... }()); </script> 

Вы можете найти подробные инструкции по использованию LoadCSS в репозитории GitHub проекта и увидеть его в действии в этой живой демонстрации .

Я склоняюсь к такому подходу: у него прогрессивное улучшение, он чистый и удобный для разработчиков.

Размещение ссылки на файлы таблицы стилей в теле документа

По словам Джейка Арчибальда, одним из недостатков предыдущего подхода является то, что он опирается на основное предположение о том, что вы или я можем считать критическим CSS . Должно быть очевидно, что все стили, примененные к вышеупомянутой части страницы сгиба, являются критическими. Однако то, что именно находится выше сгиба, почти очевидно, поскольку изменения в измерениях области просмотра влияют на количество контента, к которому пользователи могут обращаться без прокрутки. Таким образом, универсальный подход — не всегда надежное предположение.

Джейк Арчибальд предлагает другое решение , которое выглядит так:

 <head> </head> <body> <!-- HTTP/2 push this resource, or inline it --> <link rel="stylesheet" href="/site-header.css"> <header></header> <link rel="stylesheet" href="/article.css"> <main></main> <link rel="stylesheet" href="/comment.css"> <section class="comments"></section> <link rel="stylesheet" href="/about-me.css"> <section class="about-me"></section> <link rel="stylesheet" href="/site-footer.css"> <footer></footer> </body> 

Как видите, ссылки на внешние таблицы стилей размещаются не в разделе <head> а внутри <body> .

Кроме того, единственными стилями, которые отображаются сразу со страницей, либо встроенными, либо с использованием HTTP / 2 Server Push, являются стили, которые применяются к верхней части страницы. Все остальные внешние таблицы стилей размещаются непосредственно перед фрагментом HTML-контента, к которому они применяются: article.css перед <main> , site-footer.css перед <footer> и т. Д.

Вот то, к чему стремится эта техника:

План состоит в том, чтобы каждая <link rel = ”stylesheet” /> блокировала рендеринг последующего контента во время загрузки таблицы стилей, но разрешала рендеринг контента до него. Таблицы стилей загружаются параллельно, но применяются последовательно.

… Это дает вам последовательный рендеринг страницы. Вам не нужно решать, что «выше сгиба», просто включите CSS компонента страницы непосредственно перед первым экземпляром компонента.

Кажется, что все браузеры допускают размещение тегов <link> в <body> , хотя не все они ведут себя одинаково. Тем не менее, по большей части эта техника достигает своей цели.

Вы можете узнать все подробности на посту Джейка Арчибальда и посмотреть результат в этой демонстрации .

Вывод

Проблема с тем, как браузеры загружают таблицы стилей, заключается в том, что рендеринг страниц блокируется до тех пор, пока не будут получены все файлы. Это означает, что пользовательский опыт при первой посадке на веб-страницу может пострадать, особенно для тех, кто подключен к Интернету с ошибками.

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

Как вы думаете, ленивая загрузка таблиц стилей или их последовательное применение (предложение Джейка Арчибальда) работают как способ повышения скорости рендеринга страниц на вашем сайте? Какой метод вы считаете наиболее эффективным?

Нажмите на поле комментария ниже, чтобы поделиться