content-visibility: новое свойство CSS, повышающее производительность рендеринга
Свойство content-visibility
, запускаемое в Chromium 85, может быть одним из наиболее эффективных новых свойств CSS для повышения производительности загрузки страниц. content-visibility
позволяет агенту пользователя пропускать работу по визуализации элемента, включая макет и рисование, до тех пор, пока она не понадобится. Поскольку рендеринг пропускается, если большая часть вашего контента находится за пределами экрана, использование свойства content-visibility
значительно ускоряет первоначальную загрузку пользователя. Это также позволяет быстрее взаимодействовать с экранным контентом. Довольно аккуратно.
Поддержка браузера
content-visibility
полагается на примитивы в спецификации содержания CSS. Хотя на данный момент content-visibility
поддерживается только в Chromium 85 (и считается «достойным прототипирования» для Firefox), спецификация сдерживания поддерживается в большинстве современных браузеров.
CSS сдерживание
Ключевой и всеобъемлющей целью сдерживания CSS является обеспечение повышения производительности рендеринга веб-контента путем обеспечения предсказуемой изоляции поддерева DOM от остальной части страницы.
По сути, разработчик может сообщить браузеру, какие части страницы инкапсулированы как набор контента, что позволяет браузерам рассуждать о контенте без необходимости учитывать состояние вне поддерева. Знание того, какие части контента (поддеревья) содержат изолированный контент, означает, что браузер может принимать решения по оптимизации рендеринга страницы.
Есть четыре типа CSS сдерживания, каждый представляет собой потенциальную ценность для свойства CSS contain
, которые могут быть объединены вместе в разделенных пробелами список значений:
size
: Ограничение размера на элементе гарантирует, что блок элемента может быть размещен без необходимости изучения его потомков. Это означает, что мы потенциально можем пропустить макет потомков, если все, что нам нужно, - это размер элемента.layout
: Включение макета означает, что потомки не влияют на внешний макет других блоков на странице. Это позволяет нам потенциально пропустить размещение потомков, если все, что мы хотим сделать, это расположить другие блоки.style
: Включение стиля гарантирует, что свойства, которые могут оказывать влияние не только на его потомков, не покидают элемент (например, счетчики). Это позволяет нам потенциально пропустить вычисление стилей для потомков, если все, что нам нужно, - это вычислить стили для других элементов.paint
: Покраска гарантирует, что потомки содержащего бокса не будут отображаться за его пределами. Ничто не может явно переполнить элемент, и если элемент находится за пределами экрана или по иным причинам не виден, его потомки также не будут видны. Это позволяет нам потенциально пропустить рисование потомков, если элемент находится за кадром.
Пропуск рендеринга с content-visibility
Может быть сложно определить, какие значения включения использовать, поскольку оптимизация браузера может сработать только тогда, когда указан соответствующий набор. Вы можете поиграть со значениями, чтобы увидеть, что работает лучше всего, или вы можете использовать другое свойство CSS, вызываемое content-visibility
для автоматического применения необходимого сдерживания. content-visibility
гарантирует, что вы получите максимальный прирост производительности, который браузер может обеспечить, с минимальными усилиями от вас как разработчика.
Свойство content-visibility принимает несколько значений, но именно auto
обеспечивает немедленное улучшение производительности. Элемент, который имеет content-visibility: auto
получает сдерживание layout
, style
и paint
. Если элемент находится за пределами экрана (и не имеет никакого отношения к пользователю - релевантными элементами будут те, у которых есть фокус или выделение в их поддереве), он также получает сдерживание size
.
Что это значит? Короче говоря, если элемент находится за пределами экрана, его потомки не отображаются. Браузер определяет размер элемента, не учитывая его содержимое, и на этом останавливается. Большая часть визуализации, например, стили и макет поддерева элемента, пропускается.
Когда элемент приближается к области просмотра, браузер больше не добавляет вложение size
и начинает рисовать и проверять попадание содержимого элемента. Это позволяет выполнять рендеринг вовремя, чтобы пользователь мог их увидеть.
Пример: блог о путешествиях
В этом примере мы базируем наш блог о путешествиях справа и применяем егоcontent-visibility: auto
к фрагментированным областям слева. Результаты показывают, что время рендеринга увеличивается с 232 мс до 30 мс при начальной загрузке страницы.
Блог о путешествиях обычно содержит набор историй с несколькими изображениями и некоторым описательным текстом. Вот что происходит в обычном браузере, когда он переходит на блог о путешествиях:
- Часть страницы загружается из сети вместе со всеми необходимыми ресурсами.
- Браузер стилизует и размещает все содержимое страницы, не учитывая, является ли содержимое видимым для пользователя.
- Браузер возвращается к шагу 1, пока не будут загружены все страницы и ресурсы.
На шаге 2 браузер обрабатывает все содержимое в поисках вещей, которые могли измениться. Он обновляет стиль и макет любых новых элементов, а также элементов, которые могли сместиться в результате новых обновлений. Это работа по рендерингу. На это нужно время.
Теперь подумайте, что произойдет, если вы разместите content-visibility: auto
на каждую из отдельных историй в блоге. Общий цикл тот же: браузер загружает и отображает фрагменты страницы. Однако разница заключается в объеме работы, выполняемой на шаге 2.
С помощью сontent-visibility он будет стилизовать и размещать все содержимое, которое в настоящее время отображается пользователю (оно отображается на экране). Однако при обработке истории, которая полностью находится за пределами экрана, браузер пропустит работу по рендерингу и только стилизует и компоновку самого блока элемента.
Производительность загрузки этой страницы будет такой, как если бы она содержала полные экранные истории и пустые поля для каждой из закадровых историй. Это работает намного лучше, с ожидаемым снижением затрат на визуализацию загрузки на 50% или более. В нашем примере мы видим увеличение времени рендеринга с 232 мс до 30 мс. Это 7-кратный прирост производительности.
Какую работу вам необходимо выполнить, чтобы воспользоваться этими преимуществами? Сначала мы разбиваем контент на разделы:
Затем мы применяем к разделам следующее правило стиля:
.story {
content-visibility: auto;
contain-intrinsic-size: 1000px; /* Explained in the next section. */
}
Обратите внимание, что по мере того, как контент перемещается в область видимости и исчезает, он будет запускаться и перестатвать отображаться по мере необходимости. Однако это не означает, что браузеру придется отрисовывать и повторно отрисовывать один и тот же контент снова и снова, поскольку работа отрисовки сохраняется, когда это возможно.
Указание естественного размера элемента с помощью contain-intrinsic-size
Чтобы реализовать потенциальные преимущества content-visibility
, браузеру необходимо применить ограничение размера, чтобы гарантировать, что результаты рендеринга содержимого никоим образом не влияют на размер элемента. Это означает, что элемент будет выложен так, как если бы он был пустым. Если элемент не имеет высоты, указанной в обычном макете блока, он будет иметь нулевую высоту.
Это может быть не идеально, так как размер полосы прокрутки будет смещаться в зависимости от того, что каждая история имеет ненулевую высоту.
К счастью, CSS предоставляет другое свойство, contain-intrinsic-size
которое эффективно определяет естественный размер элемента, если на элемент влияет ограничение размера. В нашем примере мы устанавливаем его 1000px
как оценку высоты и ширины секций.
Это означает, что он будет располагаться так, как если бы у него был единственный дочерний элемент с размерами «внутреннего размера», гарантируя, что ваши блоки без размера по-прежнему занимают место. contain-intrinsic-size
действует как размер заполнителя вместо отображаемого содержимого.
Скрытие содержимого с помощью content-visibility: hidden
Что делать, если вы хотите, чтобы контент не отображался независимо от того, отображается он на экране или нет, используя при этом преимущества кэшированного состояния визуализации? Введите: content-visibility: hidden
.
Это свойство content-visibility: hidden
дает вам все те же преимущества необработанного содержимого и кэшированного состояния отрисовки, что и content-visibility: auto
за пределами экрана. Однако, в отличие от auto
, он не начинает автоматически отображаться на экране.
Это дает вам больше контроля, позволяя скрывать содержимое элемента, а затем быстро отображать его.
Сравните его с другими распространенными способами скрытия содержимого элемента:
display: none
: скрывает элемент и разрушает его состояние рендеринга. Это означает, что отображение элемента так же дорого, как отображение нового элемента с тем же содержимым.visibility: hidden
: скрывает элемент и сохраняет его состояние отрисовки. Это на самом деле не удаляет элемент из документа, так как он (и его поддерево) по-прежнему занимает геометрическое пространство на странице, и на него все еще можно щелкнуть. Он также обновляет состояние рендеринга в любое время, когда это необходимо, даже когда оно скрыто.
content-visibility: hidden
, с другой стороны, скрывает элемент, сохраняя его состояние отрисовки, поэтому, если есть какие-либо изменения, которые должны произойти, они произойдут только тогда, когда элемент будет показан снова (то есть свойство content-visibility: hidden
будет удалено).
Некоторые отличные варианты использования content-visibility: hidden
- это реализация продвинутых виртуальных скроллеров и макет измерения.
Заключение
content-visibility
и спецификация сдерживания CSS означают, что некоторые впечатляющие улучшения производительности идут прямо в ваш файл CSS.