20151125_56550882c1033

Однажды на хабре я прочел статью о результатах, полученных при проведении ребятами из Google различных тестов. Было выяснено, что в большинстве сценариев встраивание стилей в HTML приводит к более быстрой загрузке страницы, чем подключение стилей одним файлом. Тем не менее, такой трюк я не применял, за исключением того, что в LeadBean при генерации лендингов было реализовано встраивание стилей на страницу, что действительно немного ускоряло загрузку. При разработке обычных сайтов заморачиваться с загрузкой стилей не обязательно, но есть и такие проекты, где необходимо показать страницу пользователю как можно скорее, ведь это может улучшить аудиторные показатели. Для этого существуют, как минимум, две практики: «критический CSS» и «прогрессивный CSS».

Критический CSS

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

Обычная загрузка в head

VS

Critical CSS

При отрисовке HTML браузер, как только встречает тег <script> или <link>, останавливается и ждет пока .js или .css файл загрузится, и только после этого идет дальше. При использовании тега <script>, с помощью атрибутов async и defer , мы можем попросить браузер загружать скрипт асинхронно, без блокировки рендеринга страницы, у тега <link rel="stylesheet"> таких атрибутов нет. Из этой ситуации нас спасет функция loadCSS — ее использование позволит вашей странице отрисоваться с критическим CSS, без ожидания полной загрузки остальных стилей.

Как это работает? Если коротко, то эта функция создает тег <link rel="stylesheet"> с атрибутом media="only x". Таким образом, браузер загружает стили, при этом не блокируя рендеринг страницы. После того, как стили загружены атрибуту задается значение media="all". В современных браузерах, поддерживающих rel="preload" у тега <link>, есть возможность обойтись без loadCSS.

С media="none" такой трюк не сработает, потому что разные браузеры загружают CSS по разному, loadCSS учитывает все эти нюансы.

Прогрессивынй CSS

Прогрессивный CSS предполагает создание отдельного .css файла для каждой секции сайта, перед каждой секцией вставляется <link rel="stylesheet"> со стилем этой секции. Благодаря тому, что <link rel="stylesheet"> блокирует рендеринг до окончания загрузки стиля, страница будет загружаться последовательно по секциям. В этом сценарии, надеюсь, по понятным причинам выгодней всего использовать HTTP/2.

Пришла пора признаться, что прогрессивный CSS это скорей концепт, чем практика, и вот почему: в Спецификации HTML никак не покрыто то, как рендеринг страницы должен блокироваться загрузкой CSS, и то, как должен вести себя <link rel="stylesheet"> в <body>, поэтому разные браузеры обрабатывают <link rel="stylesheet"> в <body> по-своему. Можно выделить два основных поведения браузеров:

  1. Встретил <link rel="stylesheet"> → дождался загрузки → рендерит дальше.
  2. Встретил <link rel="stylesheet"> → дождался загрузки всех обнаруженных стилей → рендерит дальше.

Подробней про поведение каждого браузеру можно прочитать тут.

В таком виде, на реальных проектах, прогрессивный CSS в полной мере не применить, но сама концепция выглядит очень интересно.

Критический CSS + Прогрессивный CSS = gulp-progressive-css

Чтобы с легкостью применять во всех браузерах критический и прогрессивный CSS вместе, был создан плагин gulp-progressive-css. Этот плагин обрабатывает HTML-файлы, добавляя возможность использовать атрибуты priority="critical", priority="queued" и priority="async" у элемента <link rel="stylesheet">.

Стили, подключенные с атрибутом priority="critical", будут встроены в HTML файл, а стили с атрибутом priority="queued" или priority="async" будут загружены асинхронно с помощью функции importCSS. importCSS — это вариация функции loadCSS, ее особенность состоит в том, что загрузка стилей будет начата одновременно, но стили с priority="queued" будут применяться в том порядке, в котором они были указаны в HTML-файле. Чтобы загрузка стилей работала одинаково во всех браузерах, подключение стилей переносится в конец <body>. Также добавляется <link rel="preload"> в <head> для каждого стиля, чтобы в браузерах, которые поддерживают rel="preload", загрузка начиналась еще при обработке <head>.

Результаты применения

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

Тестируем изначальный вариант лендинга на PageSpeed Insights:

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

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

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

Источники: 33 способа ускорить ваш фронтенд в 2017 году, The future of loading CSS, Ускорение Lenta.ru: 3 человека, 2 недели, улучшение глубины просмотра на 27%

Seo wordpress plugin by www.seowizard.org.