Уменьшите объем и сложность расчетов стилей.

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

Расчет стиля

Изменение DOM путем добавления и удаления элементов, изменения атрибутов, классов или воспроизведения анимации приводит к тому, что браузер пересчитывает стили элементов и, во многих случаях, макет части или всей страницы. Этот процесс называется вычислением вычисляемого стиля .

Браузер начинает расчет стилей с создания набора соответствующих селекторов, чтобы определить, какие классы, псевдоселекторы и идентификаторы применимы к тому или иному элементу. Затем он обрабатывает правила стиля из соответствующих селекторов и определяет, какие окончательные стили имеет элемент.

Время пересчета стиля и задержка взаимодействия

Взаимодействие с следующей отрисовкой (INP) — это ориентированный на пользователя показатель производительности во время выполнения, который оценивает общую реакцию страницы на ввод пользователя. Он измеряет задержку взаимодействия с момента взаимодействия пользователя со страницей до момента, когда браузер рисует следующий кадр, отображающий соответствующие визуальные обновления пользовательского интерфейса.

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

Уменьшите сложность ваших селекторов

Упрощение имен селекторов может помочь ускорить расчет стиля вашей страницы. Простейшие селекторы ссылаются на элемент CSS только по имени класса:

.title {
  /* styles */
}

Но по мере роста любого проекта ему, вероятно, потребуется более сложный CSS, и в итоге вы можете получить селекторы, которые выглядят следующим образом:

.box:nth-last-child(-n+1) .title {
  /* styles */
}

Чтобы определить, как эти стили применяются к странице, браузер должен эффективно спросить: «Это элемент с классом title , родительским элементом которого является дочерний элемент минус-nth-плюс-1 с ​​классом box ?» Выяснение этого может занять много времени, в зависимости от используемого селектора и браузера. Чтобы упростить это, вы можете изменить селектор, чтобы он был просто именем класса:

.final-box-title {
  /* styles */
}

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

Уменьшите количество стилизованных элементов

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

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

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

Оцените стоимость перерасчета вашего стиля

Один из способов измерить стоимость перерасчета стилей — использовать панель производительности в Chrome DevTools. Для начала выполните следующие действия:

  1. Откройте Инструменты разработчика.
  2. Перейдите на вкладку «Производительность» .
  3. Нажмите Запись .
  4. Взаимодействуйте со страницей.

Когда вы остановите запись, вы увидите что-то вроде следующего изображения:

DevTools показывает расчеты стилей.
Отчет DevTools, показывающий расчеты стилей.

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

Увеличение масштаба проблемной области в Chrome DevTools в сводке активности заполненной панели производительности в Chrome DevTools.
Длительные кадры в сводке действий DevTools.

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

Получение подробностей длительных вычислений стилей, включая важную информацию, такую ​​как количество элементов, на которые влияет перерасчет стиля.
Длительный пересчет стиля, занимающий чуть более 25 мс в сводке DevTools.

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

Использовать блок, элемент, модификатор

Такие подходы к кодированию, как БЭМ (Блок, Элемент, Модификатор), обеспечивают преимущества в производительности, соответствующие селектору. БЭМ рекомендует, чтобы все имело один класс, а если вам нужна иерархия, эта иерархия также включается в имя класса:

.list {
  /* Styles */
}

.list__list-item {
  /* Styles */
}

Если вам нужен модификатор, как в примере с последним дочерним элементом, вы можете добавить его следующим образом:

.list__list-item--last-child {
  /* Styles */
}

БЭМ — хорошая отправная точка для организации вашего CSS как с точки зрения структуры, так и из-за упрощения поиска стилей, которое он обеспечивает.

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

Ресурсы

Героическое изображение из Unsplash , автор Маркус Списке .