
Введение
В современную цифровую эпоху производительность веб-приложения играет решающую роль в удовлетворенности и вовлеченности пользователей. Быстрота и отзывчивость сайта не только улучшают пользовательский опыт, но и повышают его рейтинг в поисковых системах и коэффициент конверсии. Это руководство поможет вам пройти путь от понимания основных концепций веб-производительности до внедрения передовых методов оптимизации фронтенда, используемых такими лидерами индустрии, как Netflix, Google и Amazon.
Начнем с изучения процесса рендеринга браузерами веб-страниц и фундаментальных концепций, влияющих на производительность сайтов. Затем погрузимся в практические методы оптимизации, постепенно переходя от доступных для новичков способов к продвинутым стратегиям.
Понимание производительности сайтов
На что влияет производительность сайта
- Удобство взаимодействия пользователей: медленная загрузка сайтов разочаровывает пользователей, что приводит к увеличению числа отказов.
- Показатели конверсии: даже односекундная задержка может значительно снизить конверсию.
- Поисковая оптимизация (SEO): поисковые системы отдают предпочтение быстрым сайтам при ранжировании.
- Возможность мобильного использования: с ростом числа мобильных браузеров оптимизация под медленные сети становится крайне важной.
Ключевые показатели производительности
Понимание показателей производительности — первый шаг к оптимизации.
- FCP (First Contentful Paint — скорость появления первого элемента контента): время, за которое отрисовывается первый текст или изображение.
- LCP (Largest Contentful Paint — скорость появления крупнейшего элемента контента): время, за которое отрисовывается самый большой текст или изображение.
- FID (First Input Delay — задержка первого ввода): время, прошедшее с момента первого взаимодействия пользователя со страницей (например, нажатия кнопки) до момента, когда браузер может ответить. FID имеет решающее значение для измерения интерактивности.
- CLS (Cumulative Layout Shift — совокупный сдвиг макета): показатель визуальной стабильности веб-страницы, отслеживающий неожиданные сдвиги макета во время загрузки. Низкий показатель CLS обеспечивает стабильность и приятное восприятие.
- TBT (Total Blocking Time — общее время блокировки): суммарное время, в течение которого основной поток блокируется, препятствуя взаимодействию с пользователем.
Как браузеры выполняют рендеринг веб-страниц
Для оптимизации производительности сайтов очень важно понимать, как браузеры преобразуют HTML, CSS и JavaScript в пиксели на экране.
Критически важный путь рендеринга (CRP)
CRP (Critical Rendering Path — критически важный путь рендеринга) — последовательность шагов, которые браузер выполняет для преобразования HTML, CSS и Javascript в реальные пиксели на экране. Оптимизация этого процесса позволяет сделать веб-страницу быстрой. Вкратце CRP — последовательность шагов, которые браузер предпринимает для рендеринга веб-страницы. CRP включает в себя:

- Парсинг HTML: создание DOM (Document Object Model — объектная модель документа).
- Парсинг CSS: создание CSSOM (CSS Object Model — объектная модель CSS).
- Выполнение JavaScript: выполнение файлов JavaScript с возможностью изменения DOM/CSSOM.
- Создание дерева рендеринга: комбинирование DOM и CSSOM.
- Компоновка макета: вычисление положения и размера элементов.
- Отрисовка: заполнение пикселей на экране.
Сначала браузер получает HTML и создает DOM. Затем он получает CSS и создает CSSOM. Эти две модели объединяются для создания дерева рендеринга (Render Tree). Далее следует этап компоновки макета (Layout), на котором браузер определяет точное положение элементов на странице. Наконец, наступает этап отрисовки (Paint), на котором пиксели выводятся на экран.

Показатель FCP в CRP
Оценка FCP происходит, когда браузер отображает первый фрагмент значимого контента. Оптимизация ранней загрузки HTML, CSS и ключевых активов (например, шрифтов, изображений героев) напрямую улучшает FCP.
Показатель LCP в CRP
Измерение LCP происходит, когда рендерится самый большой видимый контент. Задержки при загрузке CSS или больших изображений могут негативно повлиять на эту метрику. Используйте ленивую загрузку и передавайте оптимизированные активы через CDN (Content Delivery Network — сеть доставки контента), чтобы улучшить LCP.
Парсинг HTML (DOM)
Получая с сервера HTML-файл, браузер начинает читать контент строка за строкой и символ за символом. Цель — преобразовать этот необработанный текст в древовидную структуру, представляющую отношения между элементами. Этот процесс напрямую влияет на FCP, поскольку дерево DOM должно быть построено до того, как браузер сможет отобразить контент.
Для этого браузер использует токенизатор (tokenizer), который разбивает HTML на осмысленные части, называемые токенами (tokens).
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>My Website</title>
</head>
<body>
<h1>Welcome to My Website!</h1>
<img src="image.jpg" alt="A beautiful view">
</body>
</html>
Рассмотрим детально этапы HTML-парсинга.
Шаг 1: Токенизация
Токенизатор считывает HTML по одному символу за раз и генерирует токены. Они представляют собой различные элементы и фрагменты информации, содержащиеся в HTML:
- Токен начального тега: для таких тегов, как
<html>,<head>,<meta>и т. д., токенизатор выдает такие токены, какStartTag: htmlилиStartTag: head.
- Токен конечного тега: когда токенизатор встречает закрывающий тег, например
</head>, создает токенEndTag: head.
- Токены символов: для текстового контента (например
"Welcome to My Website!"— «Добро пожаловать на мой сайт!») токенизатор генерирует символьные токены.
Пример процесса токенизации
Токенизатор начинает с <!DOCTYPE html>, идентифицируя его как специальный токен doctype.
Затем он считывает <html> и выводит:
StartTag: html.
Далее считывает <head> и выводит:
StartTag: head.
Затем считывает <meta charset="UTF-8"> и выводит:
Tag: metaс атрибутом{ charset: "UTF-8" }.
Для <title>My Website</title> выводит:
StartTag: title.
Characters: My Website.
EndTag: title.
Процесс продолжается до тех пор, пока не будет токенизирован весь HTML-контент.

Шаг 2: Создание узлов и построение DOM-дерева
После того, как токенизатор сгенерировал токены, за дело берется другой инструмент, называемый конструктор дерева (tree builder). Он использует сгенерированные токены для создания объектов узлов (node objects).
- Узел — представление каждого элемента, атрибута и фрагмента текста в HTML.
- Узлы соединяются в иерархическую структуру, образуя DOM-дерево (DOM Tree).
DOM-дерево представляет структуру веб-страницы. Оно состоит из:
- Узлов элементов: представляют HTML-теги, такие как
<html>,<head>,<body>.
- Текстовых узлов: представляют текстовой контент внутри элементов, например
"Welcome to My Website!".
- Узлов атрибутов: представляют атрибуты элементов, такие как
srcтега<img>.
Как работает конструктор дерева
Конструктор дерева получает StartTag: html:
- создает узел элемента
<html>и начинает построение дерева.
Затем получает StartTag: head:
- создает узел head в качестве дочернего узла html.
Для <meta charset="UTF-8">:
- создает узел meta и присоединяет его к head;
- устанавливает атрибут
charset.
Этот процесс продолжается до тех пор, пока не будет построено все дерево.

Шаг 3: Установление взаимоотношений между узлами
Дерево DOM поддерживает отношения между узлами:
- Узлы head и body являются дочерними по отношению к узлу html.
- Узел h1 является дочерним по отношению к узлу body.
- Такие атрибуты, как
srcдля изображения, прикрепляются непосредственно к узлу img.
Эти отношения определяются вложенной структурой HTML, и дерево точно отображает, как элементы связаны друг с другом.
Инкрементное построение DOM
Важной особенностью современных браузеров является то, что они не ждут, пока загрузится весь HTML-документ, прежде чем строить DOM. Вместо этого DOM строится инкрементально, то есть браузер начинает создавать DOM-дерево, как только получает достаточно HTML для начала построения.
Например, получив <html><head><title>My Website</title></head>, браузер начнет строить узлы для html, head и title, не дожидаясь остальной части HTML-файла. Такое поэтапное построение позволяет браузеру начать рендеринг части страницы даже в то время, когда другие части еще загружаются, что ускоряет общее время загрузки страницы.
Поисковые страницы Google используют преимущества инкрементного построения DOM, оптимизируя HTML таким образом, чтобы предоставить достаточно исходной информации для начала рендеринга как можно быстрее, благодаря чему страницы кажутся пользователю быстрыми. Если вы заметили, то еще до того, как мы что-то ищем, Google загружает заголовок поиска.
2. Создание объектной модели CSS (CSSOM)
После парсинга HTML и создания объектной модели документа (DOM) браузеры переходят к обработке CSS, чтобы определить, как следует стилизовать и отобразить контент. Этот процесс включает в себя создание объектной модели CSS (CSSOM), которая необходима для конструирования дерева рендеринга. Рассмотрим подробно этапы создания браузером CSSOM.
1. Парсинг CSS:
- Когда браузер встречает тег
<link>, ссылающийся на внешнюю таблицу стилей, или тег<style>, содержащий встроенную CSS-спецификацию, он начинает выполнять парсинг CSS.
- CSS токенизируется и разбирается на правила, селекторы и декларации.
2. Образование и разбор токенов:
- Браузер считывает символы CSS по одному за раз, преобразуя их в токены (аналогично тому, как происходит парсинг HTML).
- Затем токены разбираются в структурированный формат, определяя селекторы и соответствующие им декларации стилей.
3. Обработка каскадного расположения и специфичности стилей:
- Каскадирование стилей. CSS расшифровывается как Cascading Style Sheets (каскадные таблицы стилей), что означает, что стили могут располагаться каскадом и наследоваться друг от друга. Например,
font-size: 16px, примененный к тегу<body>, будет унаследован всеми его дочерними элементами, если его не переопределить.

- Специфичность. Более специфичные селекторы имеют приоритет над менее специфичными. Например, правило
h1 { font-size: 16px; }менее специфично, чемdiv p { font-size: 12px; }. Специфические селекторы требуют от браузера пройтись по DOM-дереву, чтобы определить, какие стили применить, что делает их более затратными с вычислительной точки зрения.
/* Менее специфично */
h1 {
font-size: 16px;
}
/* Более специфично */
div p {
font-size: 12px;
}
Отступление: что такое специфичность
Специфичность в CSS — показатель, который ранжирует селекторы в зависимости от их типа и структуры. Специфичность рассчитывается на основе типов используемых селекторов, при этом больший вес имеют более специфичные селекторы.
Иерархия специфичности
Специфичность CSS классифицируется по различным типам селекторов, каждый из которых имеет свой уровень «веса». Чем выше уровень, тем больше вероятность того, что правило будет преобладать над другими. Вот распределение уровней специфичности от самого низкого до самого высокого:
1. Селекторы элементов (например, div, p, h1)
- Вес: 1 балл на селектор элементов.
- Это наименее специфичные селекторы, предназначенные для элементов, носящих имена тегов.
2. Селекторы классов, атрибутов и псевдоклассов (например, .class, [type="text"], :hover)
- Вес: 10 баллов на селектор классов или атрибутов.
- Обычно используется для стилизации групп элементов с общими характеристиками.
3. ID-селекторы (например, #header, #footer)
- Вес: 100 баллов на ID.
- Высокоспецифичные, обычно используются для уникальных элементов на странице.
4. Инлайн-стили, или встроенные стили (например, style="color: red;")
- Вес: 1000 баллов на инлайн-стиль.
- Инлайн-стили имеют самую высокую специфичность среди стандартных правил CSS.
5. !important
- При добавлении к объявлению (например,
color: red !important;) отменяет любое другое правило, независимо от специфичности.
- Используйте
!importantосторожно, так как это может затруднить поддержку CSS и устранение неполадок.
Как рассчитывается специфичность
Специфичность можно представить как ряд чисел в формате (A, B, C, D), где:
- A: количество инлайн-стилей (1 или 0);
- B: количество ID-селекторов;
- C: количество селекторов классов, атрибутов и псевдоклассов;
- D: количество селекторов элементов и псевдоэлементов.
Каждый тип селектора подсчитывается, а специфичность определяется путем сравнения этих значений. Рассмотрим несколько примеров.
Примеры расчета специфичности
Приведем несколько примеров, иллюстрирующих суть специфичности.
1. Базовый пример
/* Селектор: p (1 element selector) */
p {
color: blue;
}
/* Селектор: .content (1 class selector) */
.content {
color: green;
}
/* Селектор: #header (1 ID selector) */
#header {
color: red;
}
pимеет специфичность(0, 0, 0, 1);
.contentимеет специфичность(0, 0, 1, 0);
#headerимеет специфичность(0, 1, 0, 0).
В этом примере, если к элементу применены все три селектора, правило #header будет иметь приоритет, потому что идентификаторы (ID) обладают более высокой специфичностью, чем классы, которые, в свою очередь, имеют более высокую специфичность, чем элементы.
2. Пример со сложными селекторами
/* Селектор: div p */
div p {
color: blue;
}
/* Селектор: .main .content */
.main .content {
color: green;
}
/* Селектор: #header .content */
#header .content {
color: red;
}
div pимеет специфичность(0, 0, 0, 2);
.main .contentимеет специфичность(0, 0, 2, 0);#header .contentимеет специфичность(0, 1, 1, 0).
Здесь #header .content будет переопределять все остальное, потому что он включает ID-селектор, который имеет наибольший вес.
Общие проблемы со специфичностью и способы их избежать
1. Избегайте слишком специфических селекторов
- Слишком специфичные селекторы могут усложнить поддержку и переопределение CSS.
- Используйте классы и избегайте сложных цепочек, если в этом нет необходимости.
2. Экономно используйте идентификаторы
- Идентификаторы, поскольку имеют высокую специфичность, могут вызывать конфликты с другими селекторами.
- Отдавайте предпочтение классам для многократного использования стиля и большей гибкости.
3. Сведите к минимуму использование !important
- Чрезмерное использование
!importantможет затруднить отладку и управление CSS.
- Структурируйте CSS с учетом специфичности, чтобы избежать потребности в
!important.
Рекомендации по управлению специфичностью в больших проектах
1. Организуйте CSS с помощью методологии BEM
- Методология BEM (Block Element Modifier — блок-элемент-модификатор) обеспечивает структурированный способ организации CSS, который уменьшает конфликты специфичности.
- Пример:
.button__icon--largeимеет показатель специфичности, который легко понять и который не опирается на идентификаторы.
2. Используйте переменные CSS для согласованной стилизации
- Переменные CSS (
--main-color: blue;) снижают потребность в сложной специфичности, позволяя применять согласованную стилизацию в селекторах без риска конфликтов стилей.
3. Используйте сброс CSS или нормализацию CSS
- Сбросы CSS помогают снизить частоту конфликтов специфичности, удаляя стили, специфичные для браузера, и обеспечивая согласованную основу.
4. Внедрите инструмент линтинга для CSS
- Такие инструменты, как Stylelint, могут обеспечить соблюдение правил специфичности, гарантируя следование вашей командой согласованной структуре.
4. Создание дерева CSSOM:
- Разобранные правила CSS организуются в дерево CSSOM, которое повторяет структуру DOM, но фокусируется исключительно на стилях.
- Каждый узел в CSSOM соответствует правилу CSS, подробно описывая, какие селекторы применяются к тем или иным элементам и какие стили они должны получить.
Каскадирование и наследование
- Каскадирование. Правила CSS могут накладываться друг на друга и каскадироваться в зависимости от их специфичности и порядка. Браузер определяет окончательные стили, разрешая эти наложения, обеспечивая приоритет наиболее специфических и последних правил.
- Наследование. Некоторые свойства CSS, такие как
font-sizeиcolor, наследуются дочерними элементами от их родителей. Это означает следующее: если задатьfont-sizeв<body>, все дочерние элементы унаследуют этот размер, если он не будет явно переопределен.
body {
font-size: 16px; /* Наследуется всеми дочерними элементами */
}
p {
color: blue; /* Наследуется дочерними элементами в пределах <p> */
}
Природа CSS, блокирующая рендеринг
В отличие от DOM, CSSOM невозможно построить инкрементально. Это связано с тем, что правила CSS могут влиять на расположение и стили элементов, которые еще не прошли парсинг. Поэтому технология CSS считается блокирующей рендеринг, то есть браузер должен подождать, пока все CSS будут загружены и разобраны, прежде чем он сможет построить CSSOM и, впоследствии, дерево рендеринга.

Последствия блокировки рендеринга CSS:
- Задержка рендеринга. Если файлы CSS имеют большой размер или требуют времени для загрузки, они могут задерживать рендеринг веб-страницы, что приводит к замедлению загрузки.
- Критически важные CSS. Чтобы решить эту проблему, разработчики часто встраивают критически важные CSS (стили, необходимые для контента, видимого без прокрутки страницы) непосредственно в HTML, чтобы браузер мог быстро выполнить рендеринг начального вида.
Советы по оптимизации CSSOM для повышения производительности
1. Минимизируйте размер файлов CSS:
- Сократите объем CSS, удалив неиспользуемые стили.
- Используйте инструменты минификации для удаления пробелов и комментариев.
2. Уменьшите специфичность:
- Избегайте слишком специфичных селекторов, которые требуют от браузера дополнительных вычислений.
- Для повышения производительности используйте селекторы классов вместо селекторов потомков.
/* Избегайте */
div ul li a {
color: red;
}
/* Вместо этого используйте */
.nav-link {
color: red;
}
3. Избегайте инлайн-стилей и !important:
- Инлайн-стили и использование
!importantмогут увеличить сложность CSSOM, затрудняя браузеру определение того, какие стили следует применить.
4. Подходите рационально к использованию препроцессоров CSS:
- Такие инструменты, как Sass или LESS, могут помочь упорядочить CSS, но следите за тем, чтобы они не вносили излишней сложности или специфичности.
Управление видимостью с помощью дерева рендеринга
Дерево рендеринга строится путем объединения DOM и CSSOM. Однако не все элементы DOM включаются в дерево рендеринга. Например, элементы с display: none исключаются вместе с их дочерними элементами. Этот процесс известен как обрезка (pruning).

- Обрезка ненужных элементов: элементы, которые не видны (например,
display: none), удаляются из дерева рендеринга для оптимизации рендеринга и снижения CLS.
- Другие способы снижения CLS: 1) всегда определяйте размеры изображений и медиафайлов; 2) избегайте введения контента с отсроченной загрузкой, который смещает макеты.
.hidden {
display: none;
}
Влияние на производительность: исключая невидимые элементы, браузер уменьшает сложность дерева рендеринга, что приводит к ускорению работы над макетом и отрисовки.

Пример: сравнение производительности селекторов
Рассмотрим следующие правила CSS:
/* Менее специфичное, быстро оценивается */
h1 {
font-size: 16px;
}
/* Более специфичное, медленнее оценивается */
div p {
font-size: 12px;
}
Селектор h1:
- Предназначен для всех элементов
<h1>.
- Просто и быстро согласуется с браузером.
Селектор div p:
- Предназначен для элементов
<p>, которые являются потомками<div>.
- Браузеру требуется обойти DOM-дерево, чтобы убедиться, что
<p>находится в пределах<div>.
- Нуждается в больших вычислительных затратах из-за повышенной специфичности.
Лучшие практики:
- Для повышения производительности используйте более простые селекторы, основанные на классах.
- Ограничьте глубину селекторов-потомков, чтобы сократить время обхода DOM-дерева.
Читайте также:
- Производительность фронтенда: лав-стори для разработчиков
- 17 революционных инструментов для фронтенда, о которых вы должны знать в 2025 году
- Практики фронтенд-разработки, которые помогут избежать неудач
Читайте нас в Telegram, VK и Дзен
Перевод статьи Saquib Khan: How to Build Websites That Load Before You Blink: Frontend Optimization Tips





