От автора: после того как браузер получает HTML ответ от сервера, проходит еще множество этапов перед отрисовкой пикселей на экране. Последовательность действий, которую должен пройти браузер для первичной отрисовки страницы называется «путь критического рендеринга» или CRP.
Знание CRP невероятно полезно для понимания того, как можно улучшить производительность сайта. CRP проходит 6 этапов:
построение дерева DOM;
построение дерева CSSOM;
запуск JavaScript;
создание дерева рендеринга;
генерация макета;
отрисовка.
Построение дерева DOM
Дерево DOM (Document Object Model) – это объектное представление полностью распарсеной HTML страницы. Узлы создаются для каждого элемента/текста на странице, начиная от корневого элемента . Вложенные элементы представляются в виде дочерних узлов, все узлы хранят все атрибуты элементов. Например, тег a будет иметь атрибут href, привязанный к своему узлу.
Разберем для примера этот простой документ:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<html> <head> <title>Understanding the Critical Rendering Path</title> <link rel="stylesheet" href="style.css"> </head> <body> <header> <h1>Understanding the Critical Rendering Path</h1> </header> <main> <h2>Introduction</h2> <p>Lorem ipsum dolor sit amet</p> </main> <footer> <small>Copyright 2017</small> </footer> </body> </html> |
Код создает следующее дерево DOM:
Чем хорош HTML – его можно выполнять частями. Не нужно загружать весь документ, чтобы начать отрисовывать контент на странице. Однако другие ресурсы, например, CSS и JS могут блокировать рендеринг.
Построение дерева CSSOM
CSSOM (CSS Object Model) представляет собой объектное представление стилей DOM. Представление очень похоже на DOM, только к узлам добавляются стили, будь то явно прописанные или неявно унаследованные.
Для документа выше у нас есть файл style.css со следующими стилями:
1 2 3 4 5 6 7 8 9 |
body { font-size: 18px; } header { color: plum; } h1 { font-size: 28px; } main { color: firebrick; } h2 { font-size: 20px; } footer { display: none; } |
Стили создают следующее дерево CSSOM:
CSS считается ресурсом, блокирующим рендеринг. То есть дерево рендеринга (см. ниже) не построится, пока не распарсится этот ресурс. Из-за своей каскадной природы CSS нельзя использовать частями, в отличие от HTML. Стили, объявленные в файле ниже, могут переписать значения и изменить предыдущие стили. Если мы будем использовать стили, объявленные сверху в файле, не дождавшись полного парсинга, это может привести к тому, что будут применены не те стили. CSS должен быть полностью распарсен перед тем, как переходить к следующему этапу.
CSS файлы считаются ресурсами, блокирующими рендеринг только, когда они применяются к текущему устройству. Тег <link rel=»stylesheet»> принимает атрибут media, в котором можно указать любой медиа запрос, внутри которого будут применяться стили. Если, например, у нас есть стили с медиа атрибутом orientation:landscape, а мы просматриваем страницу в портретном режиме, то данный ресурс не будет считаться блокирующим рендеринг.
CSS может также блокировать скрипты. JS файлы должны подождать, пока построится CSSOM.
Запуск JavaScript
JS считается ресурсом, блокирующим парсер. То есть парсинг HTML документа блокируется JS.
Когда парсер доходит до тега script, будь то внутренний или внешний, он останавливается и вытягивает код (если файл внешний) и запускает его выполнение. Вот почему необходимо размещать скрипты в конце документа, если они ссылаются на элементы.
Чтобы не блокировать парсер, JS можно загружать асинхронно с помощью атрибута async.
1 |
<script async src="script.js"> |
Создание дерева рендеринга
Дерево рендеринга состоит из DOM и CSSOM. Это дерево представляет ровно то, что будет показываться на странице. Это означает, что в это дерево попадает только видимый контент. Оно не будет включать, например, элементы, скрытые через CSS с помощью свойства display: none.
По DOM и CSSOM выше будет создано следующее дерево рендеринга:
Генерация макета
Макет определяет размер вьюпорта, который дает контекст для CSS стилей, которые в свою очередь зависят от макета. Будь то проценты или единицы vw. Размер вьюпорта задается с помощью мета тега viewport в хедере документа. Если тег отсутствует, ширина вьюпорта по умолчанию составляет 980px.
Например, самое популярное значение вьюпорта – это чтобы его размер соответствовал ширине устройства:
1 |
<meta name="viewport" content="width=device-width,initial-scale=1"> |
Если пользователь зайдет на страницу с устройства с шириной, например, 1000px, то размеры будут в этих единицах. Половина вьюпорта будет равна 500px, 10vw будут составлять 100px и т.д.
Отрисовка
На финальном этапе отрисовки видимый контент страницы конвертируется в пиксели на экране.
Время отрисовки зависит от размера DOM и применяемых стилей. Некоторые стили занимают больше времени, чем другие. Например, сложный градиент background-image требует на отрисовку больше времени, чем обычный сплошной фон.
Собираем все вместе
В панели разработчика можно посмотреть путь критического рендеринга в действии. В Chrome это можно сделать на вкладке Timeline (в Canary и будущей стабильной версии Chrome эта вкладка переименована в Performance).
Возьмем для примера наш HTML из примера выше (с тегом script):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<html> <head> <title>Understanding the Critical Rendering Path</title> <link rel="stylesheet" href="style.css"> </head> <body> <header> <h1>Understanding the Critical Rendering Path</h1> </header> <main> <h2>Introduction</h2> <p>Lorem ipsum dolor sit amet</p> </main> <footer> <small>Copyright 2017</small> </footer> <script src="main.js"></script> </body> </html> |
Если взглянуть на логи событий загрузки страницы, мы увидим следующую картину:
Send Request – послан GET запрос для index.html
Parse HTML и Send Request – начинаем парсить HTML и создаем DOM. Посылаем GET запрос для style.css и main.js
Parse Stylesheet – для style.css создается CSSOM
Evaluate Script – сканируется main.js
Layout – генерируется макет на основе мета тега вьюпорт в HTML
Paint – отрисовка пикселей в документе
Зная эту информацию, мы можем продумать оптимизацию пути критического рендеринга. В будущих статьях я расскажу про пару техник.
Источник: //bitsofco.de/
Редакция: Команда webformyself.