JavaScript часто является триггером для визуальных изменений. Иногда эти изменения происходят напрямую через манипуляции со стилями, а иногда — через вычисления, приводящие к визуальным изменениям, например, поиск или сортировка данных. Несвоевременное или длительное выполнение JavaScript может быть распространенной причиной проблем с производительностью, поэтому следует стремиться минимизировать его влияние, где это возможно.
Расчет стиля
Изменение DOM-структуры путем добавления и удаления элементов, изменения атрибутов, классов или воспроизведения анимаций приводит к тому, что браузер пересчитывает стили элементов и, во многих случаях, макет части или всей страницы. Этот процесс называется вычислением стилей .
Браузер начинает вычисление стилей, создавая набор соответствующих селекторов, чтобы определить, какие классы, псевдоселекторы и идентификаторы применяются к любому заданному элементу. Затем он обрабатывает правила стилей из соответствующих селекторов и определяет, какие окончательные стили получит элемент.
Роль перерасчета стиля в задержке взаимодействия
Interaction to Next Paint (INP) — это ориентированная на пользователя метрика производительности во время выполнения, которая оценивает общую отзывчивость страницы к пользовательскому вводу. Она измеряет задержку взаимодействия с момента взаимодействия пользователя со страницей до момента отрисовки браузером следующего кадра, отображающего соответствующие визуальные обновления пользовательского интерфейса.
Важным компонентом взаимодействия является время, необходимое для отрисовки следующего кадра. Работа по рендерингу, выполняемая для отображения следующего кадра, состоит из множества частей, включая вычисление стилей страницы, которое происходит непосредственно перед компоновкой, отрисовкой и композитингом. Это руководство фокусируется на затратах на вычисление стилей, но сокращение любой части общего времени рендеринга взаимодействия также уменьшает его общую задержку.
Уменьшите сложность ваших селекторов.
Упрощение CSS-селекторов может ускорить вычисления стилей вашей страницы. Простейшие селекторы ссылаются на элемент в CSS только по имени класса:
.title {
/* styles */
}
Но по мере развития любого проекта, вероятно, потребуется более сложный CSS, и в итоге вы можете получить селекторы, которые выглядят примерно так:
.box:nth-last-child(-n+1) .title {
/* styles */
}
Чтобы определить, как эти стили применяются к странице, браузеру фактически приходится спрашивать: «Является ли это элементом с классом title , родительским элементом которого является элемент с классом box , являющийся минус n-м плюс 1-м дочерним элементом своего родительского элемента?» Выяснение этого может занять у браузера некоторое время. Чтобы упростить задачу, можно изменить селектор, указав более конкретное имя класса:
.final-box-title {
/* styles */
}
Эти заменяющие имена классов могут показаться неудобными, но они значительно упрощают работу браузера. В предыдущей версии, например, чтобы браузер понял, что элемент является последним в своем типе, он должен был сначала узнать все об остальных элементах, чтобы определить, могут ли какие-либо элементы, следующие за ним, быть nth-last-child . Это может быть гораздо более ресурсоемким с точки зрения вычислений, чем сопоставление селектора с элементом исключительно на основе его имени класса.
Уменьшите количество элементов, подвергающихся стилизации.
Ещё один фактор, влияющий на производительность, — и зачастую более важный, чем сложность селектора, — это объём работы, который необходимо выполнить при изменении элемента.
В общем, в худшем случае затраты на вычисление стиля элемента равны количеству элементов, умноженному на количество селекторов, поскольку браузеру необходимо проверить каждый элемент как минимум один раз на соответствие каждому стилю, чтобы убедиться в этом.
Вычисления стилей могут напрямую воздействовать на несколько элементов, а не аннулировать всю страницу. В современных браузерах это, как правило, менее проблематично, поскольку браузеру не всегда нужно проверять все элементы, на которые может повлиять изменение. Более старые браузеры, с другой стороны, не всегда оптимизированы для таких задач. По возможности следует уменьшить количество аннулируемых элементов .
Оцените стоимость перерасчета вашего стиля.
Существует несколько способов измерения стоимости пересчета стилей в браузере. Каждый из них зависит от того, хотите ли вы измерить это в браузере в вашей среде разработки или же хотите измерить, сколько времени этот процесс занимает у реальных пользователей вашего веб-сайта.
Измерение стоимости пересчета стилей в инструментах разработчика Chrome.
Один из способов оценить стоимость перерасчета стилей — использовать панель производительности в инструментах разработчика Chrome. Для начала выполните следующие действия:
- Откройте инструменты разработчика.
- Перейдите на вкладку «Производительность» .
- Установите флажок «Статистика селектора» (необязательно).
- Нажмите «Запись» .
- Взаимодействуйте со страницей.
Когда вы остановите запись, вы увидите примерно следующее изображение:

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

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

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

Эта панель предоставляет полезные данные об относительной стоимости каждого селектора, позволяя определить дорогостоящие CSS-селекторы.
Для получения более подробной информации см. документацию по статистике селекторов CSS .
Измерьте стоимость перерасчета стиля для реальных пользователей.
Если вам интересно узнать, сколько времени занимает перерасчет стилей для реальных пользователей вашего сайта, API Long Animation Frames предоставляет вам необходимые инструменты для этого. Данные из этого API были добавлены в библиотеку JavaScript web-vitals , включая время перерасчета стилей.
Если вы подозреваете, что задержка отображения интерактивного элемента является основной причиной задержки отображения страницы (INP), вам следует выяснить, сколько времени тратится на пересчет стилей на странице. Для получения дополнительной информации ознакомьтесь с тем , как измерить время пересчета стилей в реальных условиях .