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

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

Джереми Вагнер
Джереми Вагнер
Пол Льюис

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

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

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

Краткое содержание

  • Как сокращение затрат на расчет стиля может снизить задержку взаимодействия.
  • Уменьшите сложность ваших селекторов; используйте классо-ориентированную методологию (например, БЭМ).
  • Уменьшите количество элементов, по которым необходимо рассчитывать расчет стиля.

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

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

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

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

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

.title {
  /* styles */
}

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

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

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

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

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

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

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

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

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

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

Один из способов измерить стоимость перерасчета стилей — использовать панель производительности в Chrome DevTools. Для начала откройте DevTools, перейдите на вкладку « Производительность» , нажмите «Запись» и взаимодействуйте со страницей. Когда вы остановите запись, вы увидите что-то вроде изображения ниже:

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

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

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

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

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

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

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

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

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

.list {
  /* Styles */
}

.list__list-item {
  /* Styles */
}

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

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

Если вы ищете хороший способ организовать свой CSS, BEM — хорошая отправная точка, как с точки зрения структуры, так и из-за упрощения поиска стилей, которое предлагает эта методология.

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

Ресурсы

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