Автор: Хуан Хаоцюнь
Кровавый случай, вызванный свойством CSS
Производительность веб-страницы находится в центре внимания фронтенд-разработки. Существует множество показателей для оценки производительности интерфейсных веб-страниц. Беглость страницы — один из них. Как сделать страницу «мягкой и шелковистой» обсуждение Интересная тема. При разработке мобильной страницы H5 ранее я столкнулся с интересной проблемой производительности: на мобильных телефонах IOS у определенной страницы магазина было серьезное зависание, но на моделях Android она работала очень плавно. Суммируйте конкретную производительность, протестированную на iPhoneX:
-
При загрузке страницы происходит значительная задержка, но сетевой запрос, перехваченный через прокси, занимает не больше времени, чем Android;
-
При прокрутке страницы появляется кратковременный частичный белый экран, представляющий собой пропущенный кадр.
Основываясь на этих характеристиках, нетрудно сделать вывод, что должно быть что-то, лихорадочно занимающее центральный процессор и блокирующее процесс рендеринга.
Однако, что именно, если вы спросите меня, я не знаю. Я боюсь, что для такого рода проблем, которые не могут быть обнаружены с помощью точек останова, можно справиться только с «дихотомией кода», переданной предками. После некоторого кропотливого расследования основная причина проблемы, наконец, сосредоточилась на следующей строке кода CSS:
filter: blur(100px);
Эта строка кода CSS реализует размытие по Гауссу для создания нижней тени модуля купона. Поскольку действие настроено с несколькими купонами, на странице установлено несколько элементов div с этим атрибутом, и браузеру мобильного телефона IOS очень сложно отобразить этот атрибут (однако причина трудности неизвестна), что приводит к слишком высокой загрузке ЦП процессом рендеринга, что в конечном итоге приводит к зависанию.
Ой? ЦП слишком загружен? Легко сделать! Я добавил еще одну строку кода в модуль купона, и проблема исчезла...
will-change: transform;
Вы правильно прочитали, я не написал слишком много, это действительно решается одной строкой кода.
Люди, которые его знают, возможно, видели его. Общий принцип на самом деле очень прост. Эта строка кода может включить отрисовку страниц с ускорением на графическом процессоре, что значительно снижает нагрузку на ЦП и достигает цели оптимизации производительности отрисовки страниц. Если вы этого не сделаете, Чтобы понять аппаратное ускорение CSS, вы можете ознакомиться с этой статьей.Повысьте производительность своего сайта с помощью CSS с аппаратным ускорением.
Проблема решена, но действительно ли это конец? В соответствии с великим принципом «вытягивать деревья и находить корни», я хорошо изучил эту вещь, но обнаружил, что ускорение GPU не так просто.
Процесс рендеринга в браузере
Прежде чем подробно обсудить принцип, нам нужно понять некоторые основные концепции процесса рендеринга в браузере. Процесс рендеринга в браузере является общей темой.На такие вопросы, как «как браузер отображает содержимое страницы», многие люди могут рассказать относительно полный процесс, от сетевых запросов до синтаксического анализа браузера, который может быть специфичным для множества деталей. . Помимо этапов получения сетевых ресурсов, отображение веб-страниц, которые мы понимаем, обычно можно разделить на构建 DOM 树
,构建渲染树
,布局
,绘制
,渲染层合成
несколько шагов.
-
Построение дерева DOM: Браузер анализирует HTML в дерево DOM с древовидной структурой.Вообще говоря, этот процесс происходит при первой загрузке страницы или когда JavaScript страницы изменяет структуру узла.
-
Построить дерево рендеринга: Браузер анализирует CSS в древовидное дерево CSSOM, а затем объединяет его с деревом DOM в дерево рендеринга.
-
Макет: Браузер вычисляет положение каждого узла на экране в соответствии с узлами, воплощенными в дереве рендеринга, определениями CSS каждого узла и их принадлежностью. Расположение элементов на веб-странице является относительным. Изменения положения и размера элементов на странице часто приводят к привязке других узлов, и макет необходимо пересчитывать. Процесс макета в настоящее время обычно называется перекомпоновкой.
-
Draw (Paint): обход дерева рендеринга, вызов рендерера
paint()
Метод рисует содержимое узла на экране, что по сути является процессом заполнения пикселей. Этот процесс также происходит при частичных перерисовках экрана, вызванных перерисовками или некоторыми изменениями CSS, не влияющими на верстку, в настоящее время он называется перерисовкой (Repaint). На самом деле процесс рисования выполняется на нескольких слоях, которые мы называем RenderLayer. -
Состав слоев рендеринга (композитный): несколько слоев рендеринга объединяются в соответствующем порядке перекрытия, а затем генерируется растровое изображение, которое, наконец, отображается на экране через графическую карту.
Это базовый процесс браузера от синтаксического анализа до отрисовки веб-страницы, связанный с решением проблемы зависания страницы выше, в основном последняя ссылка - синтез слоя рендеринга.
Наложение слоя рендеринга
1. Что такое композиция слоя рендеринга
Каждый узел в DOM-дереве соответствует объекту рендеринга (RenderObject), когда их объекты рендеринга находятся в одном координатном пространстве (пространстве оси z), формируется RenderLayers, то есть слой рендеринга. Слой рендеринга гарантирует, что элементы страницы расположены в правильном порядке, и именно здесь происходит композиция слоев, которая правильно обрабатывает отображение прозрачных и перекрывающихся элементов.
Эта модель похожа на модель слоев Photoshop.В Photoshop каждый элемент дизайна представляет собой независимый слой, и несколько слоев накладываются друг на друга в пространстве по оси Z в правильном порядке, чтобы в конечном итоге сформировать законченный дизайн.
Этот процесс особенно важен для страниц с перекрывающимися элементами, потому что, если слои объединены в неправильном порядке, элементы будут отображаться неправильно.
Во-вторых, принцип рендеринга в браузере
Из процесса рендеринга браузера мы знаем, что HTML-код страницы будет преобразован в дерево DOM, и каждый элемент HTML соответствует узлу в древовидной структуре. От дерева DOM к слою рендеринга один за другим и, наконец, для выполнения процесса слияния и рисования, в середине фактически есть некоторые переходные структуры данных, которые записывают принцип преобразования дерева DOM в экранную графику и его Суть в том, что древовидная структура эволюционирует в структуру слоев.
1. РендерОбъект
Узел DOM соответствует объекту рендеринга, а объект рендеринга по-прежнему поддерживает древовидную структуру дерева DOM. Объект рендеринга знает, как отрисовывать содержимое узла DOM, и рисует узел DOM, выдавая необходимые вызовы отрисовки графическому контексту (GraphicsContext).
2. Рендер-слой
Это первая модель слоя, построенная во время рендеринга в браузере. Объекты рендеринга в одном координатном пространстве (пространстве оси Z) будут объединены в один и тот же слой рендеринга. Поэтому, в соответствии с контекстом наложения, рендеринг объектов в разных координатных пространствах будет множественным. Слои рендеринга формируются, чтобы отразить их каскадные отношения. Поэтому для отрисовки объектов, удовлетворяющих условиям формирования контекста наложения, браузер автоматически создаст для них новый слой отрисовки. Общие ситуации, которые могут привести к тому, что браузер создаст для него новый слой рендеринга, включают следующее:
-
документ корневого элемента
-
Иметь явные атрибуты позиционирования (относительное, фиксированное, липкое, абсолютное)
-
opacity < 1
-
Имеет свойство CSS fliter
-
Имеет свойство маски CSS
-
Имеет свойство CSS mix-blend-mode со значением, отличным от нормального
-
Имеет свойство преобразования CSS со значением, отличным от none
-
свойство backface-visibility скрыто
-
Имеет свойство отражения CSS
-
Имеет свойство CSS column-count и значение не auto или имеет свойство CSS column-width и значение не auto
-
В настоящее время применяются анимации для непрозрачности, преобразования, флитера, фонового фильтра.
-
перелив не виден
Существует однозначное соответствие между узлами DOM и объектами рендеринга, и объекты рендеринга, отвечающие вышеуказанным условиям, могут иметь независимый слой рендеринга. Конечно, независимость здесь не совсем точна, и это не означает, что они полностью разделяют слой рендеринга, так как объект рендеринга, не удовлетворяющий вышеуказанным условиям, будет иметь один и тот же слой рендеринга со своим первым родительским элементом, имеющим слой рендеринга. слой, фактический слой рендеринга, эти объекты рендеринга будут совместно использовать этот слой рендеринга с некоторыми его дочерними элементами.
3. Графический слой
GraphicsLayer на самом деле представляет собой модель слоя, отвечающую за генерацию финальной графики контента для рендеринга.Он имеет графический контекст (GraphicsContext), а GraphicsContext отвечает за вывод растрового изображения слоя. Растровое изображение, хранящееся в общей памяти, будет загружено в графический процессор в виде текстуры, и, наконец, графический процессор синтезирует несколько растровых изображений и отрисовывает их на экран, в это время наша страница будет отображаться на экране.
Итак, GraphicsLayer — важный носитель и инструмент рендеринга, но он имеет дело не напрямую со слоями рендеринга, а со слоями компоновки.
4. Композитный слой
Слои рендеринга, отвечающие определенным особым условиям, будут автоматически преобразованы браузером в составные слои. Композитный слой имеет отдельный GraphicsLayer, в то время как другие слои рендеринга, которые не являются композитными слоями, совместно используют один слой с первым родительским слоем, имеющим GraphicsLayer.
Итак, каким особым условиям должен соответствовать слой рендеринга, прежде чем его можно будет повысить до составного слоя? Вот несколько распространенных случаев:
-
3D-преобразования: translate3d, translateZ и т. д.
-
Такие элементы, как видео, холст, iframe и т. д.
-
Анимированные переходы непрозрачности с помощью Element.animate()
-
Анимированные переходы непрозрачности с помощью анимации СSS
-
position: fixed
-
Обладает свойством изменения воли
-
Прикладная анимация или переход к непрозрачности, трансформации, флитеру, фоновому фильтру
Таким образом, решение в первом примере фактически состоит в том, чтобы использовать свойство will-change для обновления элементов рендеринга, интенсивно использующих ЦП, до нового слоя композиции, чтобы включить ускорение графического процессора, поэтому вы также можете использоватьtransform: translateZ(0)
Для решения этой проблемы.
Здесь стоит отметить, что многие люди путают условия этих составных слоев с условиями, созданными слоем рендеринга.Эти два условия возникают в двух разных ссылках обработки слоев и совершенно различны.
Кроме того, в некоторых статьях CSS-фильтр упоминается как один из факторов, влияющих на Composite, но я обнаружил, что после проверки он не оказывает никакого влияния.
3. Неявный синтез
Как упоминалось выше, при выполнении определенных явных особых условий слой рендеринга будет повышен браузером до составного слоя. Кроме того, на этапе Composite браузера также присутствует неявный композит, и некоторые слои рендеринга будут по умолчанию повышены до составных слоев в некоторых конкретных сценариях.
Для неявного синтезаCSS GPU AnimationОн описывается таким образом:
Это называется неявным композитингом: один или несколько некомпозитных элементов, которые должны располагаться над составным элементом в порядке наложения, продвигаются к составным слоям. (Один или несколько несоставных элементов должны располагаться над составными элементами в порядке наложения, чтобы их можно было повысить до составного слоя.)
Это предложение может быть трудным для понимания, на самом деле оно описывает проблему перекрытия (перекрытия). Чтобы проиллюстрировать на примере:
- Два элемента div с абсолютным позиционированием перекрываются на экране в соответствии с
z-index
отношения, один из div будет «переопределять» другой.
- В это время, если div ниже добавляется со свойствами CSS:
transform: translateZ(0)
, он будет преобразован браузером в составной слой. Обновленный слой композиции расположен над документом. Если неявной композиции нет, то div, который должен быть над ним, по-прежнему использует тот же GraphicsLayer, что и документ, а вместо этого уровень понижается, что приводит к путанице в перекрывающихся отношениях элементов. .
- Таким образом, чтобы исправить неправильный порядок перекрытия, браузер должен сделать так, чтобы слой рендеринга, который должен был быть «наложен» поверх него, одновременно повышался до слоя композиции.
В-четвертых, взрыв слоя и сжатие слоя
1. Взрыв слоя
Из приведенного выше исследования мы можем обнаружить, что некоторые причины создания синтетических слоев слишком скрыты, особенно неявный синтез. В обычном процессе разработки мы редко обращаем внимание на проблему синтеза слоев, и легко создать некоторые слои синтеза, которые не находятся в ожидаемом диапазоне.Когда эти слои синтеза, которые не соответствуют ожиданиям, достигают определенного порядка величины, они станут слоями, взорвутся.
Взрыв уровня задействует GPU и много ресурсов памяти, серьезно снижая производительность страницы, поэтому слепое использование GPU-ускорения может быть контрпродуктивным.Аппаратное ускорение CSS3 тоже имеет свои недостатки.В этой статье представлен интересныйDEMO, страница DEMO содержит заголовок h1, который анимирует преобразование, что, в свою очередь, вызывает его визуализацию в слое композитинга. Из-за специфики преобразования анимации (динамическое перекрытие не определено) неявный синтез также может происходить без перекрытия, в результате чего всеz-index
Слои рендеринга, соответствующие узлам, расположенным выше, превращаются в составные слои, и, наконец, на этой странице генерируются тысячи составных слоев.
Устранение неявной композиции должно устранить перекрытие элементов.Возьмите это DEMO в качестве примера, нам нужно только указать заголовок h1z-index
Установка более высокого значения для атрибута может сделать его выше, чем у других элементов на странице, и, естественно, нет необходимости обновлять слой композиции. Нажмите кнопку «Проверить» в DEMO, чтобы добавить заголовок h1 большего размера.z-index
, контраст между до и после очень очевиден.
2, сжатие слоя
Конечно, перед лицом этой проблемы у браузеров также есть соответствующие стратегии.Если несколько слоев рендеринга перекрываются с одним и тем же составным слоем, эти слои рендеринга будут сжаты в GraphicsLayer, чтобы предотвратить возможный «взрыв» слоя. Это предложение нелегко понять, давайте посмотрим на этот пример:
- Это та же модель, что и раньше, только на этот раз разница в том, что на экране есть четыре блока div с абсолютным позиционированием. На данный момент в div внизу добавлены свойства CSS.
transform: translateZ(0)
После этого он продвигается браузером на составной слой.По принципу неявной композиции, div над ним продвигается на новый составной слой, а третий div размещается поверх второго, что естественно продвигаться.Для композитного слоя четвертый то же самое. Таким образом, не будет ли четыре составных слоя?
- Однако это не так.Механизм сжатия слоев браузера будет сжимать несколько слоев рендеринга, которые неявно синтезируются в один и тот же GraphicsLayer для рендеринга, то есть три приведенных выше элемента div в конечном итоге окажутся в одном и том же слое композиции. сжатие слоя.
Конечно, автоматическое сжатие слоев в браузере не является панацеей, во многих конкретных случаях браузер не может выполнять сжатие слоев.Оптимизация производительности беспроводной сети: КомпозитныйВ этой статье перечислено множество подробных сценариев.
Оптимизация рендеринга страницы на основе композиции слоев
1. Плюсы и минусы синтеза слоя
Составление слоев — относительно сложная функция браузера, зачем нам сосредотачиваться на чем-то таком низкоуровневом и сложном для понимания? Это потому, что после того, как слой рендеринга будет повышен до составного слоя, это принесет нам много преимуществ:
-
Растровое изображение составного слоя будет скомпоновано графическим процессором, который намного быстрее обработки процессором;
-
Когда требуется перерисовка, требуется только перерисовка, и другие слои не будут затронуты;
-
После того, как элемент будет переведен в составной слой, преобразование и непрозрачность не вызовут перерисовку.Если это не составной слой, он все равно вызовет перерисовку.
Конечно, плюсы и минусы относительны и сосуществуют, а синтез слоев также имеет некоторые недостатки, которые часто становятся основной причиной проблем с производительностью нашей веб-страницы:
-
Нарисованные слои необходимо передавать на GPU, и когда количество и размер этих слоев достигает определенного уровня, передача может быть очень медленной, что, в свою очередь, может вызвать мерцание на некоторых бюджетных и средних устройствах;
-
Неявный композитинг склонен к чрезмерному количеству слоев композитинга, каждый из которых занимает дополнительную память, а память является ценным ресурсом на мобильных устройствах Чрезмерное использование памяти может привести к сбою браузеров и сделать оптимизацию производительности контрпродуктивной.
2. Как Chrome Devtools просматривает слои синтеза
Функция композиции слоев предоставляет нам способ оптимизировать производительность страницы с помощью аппаратных возможностей терминала.Для некоторых страниц с интенсивным взаимодействием и интенсивной анимацией рациональное использование композиции слоев может значительно повысить эффективность рендеринга страницы и улучшить интерактивность. . На что нам нужно обратить внимание, так это на то, как избежать негативного влияния синтеза слоя на страницу, или, говоря иначе, как сбалансировать интересы и рационально организовать слой синтеза страницы, что требует от нас анализа слоя синтез страницы заранее.Есть детальное понимание. Chrome Devtools предоставляет нам некоторые инструменты для простого просмотра слоя композиции страницы.
Во-первых, посмотрите на рендеринг страницы, взяв за пример страницу столбца, нажмитеMore tools -> Rendering
,выберитеLayer borders
, вы можете видеть, что все слои композиции на странице обрамлены желтым цветом.
Этого недостаточно, нам также нужна более подробная ситуация синтеза слоев, нажмитеMore tools -> Layers
, вы можете увидеть такое представление:
Слева находится список всех элементов, повышенных до отдельных слоев композитинга, а справа — общий вид границы слоя композитинга, а также сведения о выбранном слое композитинга, включая следующую ключевую информацию:
- Размер: размер составного слоя, фактически равный размеру соответствующего элемента;
- Причины формирования композитного слоя: причина образования композитного слоя является наиболее критической, а также является точкой прорыва для нас в анализе проблемы.Например, причиной композитного слоя на рисунке является проблема перекрытия;
- Оценка памяти: оценка использования памяти;
- Paint count: количество розыгрышей;
- Области медленной прокрутки: области медленной прокрутки.
Видно, что мы непреднамеренно создали множество неожиданных составных слоев, и эти нереалистичные составные слои можно оптимизировать.
3. Некоторые предложения по оптимизации
1. Анимация реализована с помощью трансформации
Для некоторых ключевых анимаций с высокими требованиями к опыту, таких как некоторые интерактивные и сложные страницы игрового процесса, есть элементы анимации, которые постоянно меняют свое положение, лучше использовать преобразование вместо изменения метода слева/сверху. Причина этого в том, что если вы используете left/top для изменения положения, узел анимации и документ будут помещены в один и тот же GraphicsLayer для рендеринга, а эффект непрерывной анимации заставит весь документ непрерывно перерисовываться, и если вы используйте преобразование. Узел анимации можно поместить в отдельный слой композиции для рендеринга и рисования, и анимация не повлияет на другие слои, когда она произойдет. А с другой стороны, анимация будет полностью выполняться на графическом процессоре, что часто более плавно, чем если бы процессор обрабатывал слой, а затем отправлял его на графическую карту для отображения.
2. Уменьшите неявный синтез
Хотя неявный синтез в основном обеспечивает правильный порядок перекрытия слоев, в реальной разработке неявный синтез может легко привести к созданию некоторых бессмысленных слоев синтеза.В конечном счете, мы должны ограничивать себя во время разработки. наступая на ямы.
Например, на странице столбца, упомянутой выше, на странице создается слишком много составных слоев из-за неаккуратной разработки страницы.Когда я пытаюсь проверить составной слой страницы, я уже чувствую зависание на ПК. Проанализировав с помощью Chrome Devtools, нетрудно обнаружить, что на странице есть кнопка с анимированной трансформацией, которая продвигается на композитный слой.Неопределенность перекрытия анимации делает другие на страницеz-index
Узлы, которые больше его, но на самом деле не перекрываются, также все продвигаются на уровень синтеза (эта причина действительно хороша).
На данный момент нам нужно только поместить узел анимацииz-index
Задайте для свойства большее значение, чтобы порядок размещения был выше, чем у других нерелевантных узлов на странице. Конечно не вслепуюz-index
иногда можно избежатьz-index
Это все равно приведет к неявному синтезу.В это время вы можете попробовать настроить порядок узлов в документе и позволить более поздним узлам покрывать предыдущие, не используяz-index
для настройки отношения перекрытия. Метод не уникален, и конкретный метод все еще должен быть проанализирован по разным страницам.
Эффект улучшенной страницы следующий, вы можете видеть, что мы устранили много бессмысленных синтетических слоев по сравнению с до оптимизации.
3. Уменьшите размер составного слоя
В качестве простого примера нарисуйте два div одинакового размера, но реализация немного отличается: один напрямую задает размер 100x100, другой задает размер 10x10, а затем передаетscale
Увеличьте масштаб в 10 раз, и мы позволим обоим элементам div превратиться в составные слои:
<style>
.bottom, .top {
position: absolute;
will-change: transform;
}
.bottom {
width: 100px;
height: 100px;
top: 20px;
left: 20px;
z-index: 3;
background: rosybrown;
}
.top {
width: 10px;
height: 10px;
transform: scale(10);
top: 200px;
left: 200px;
z-index: 5;
background: indianred;
}
</style>
<body>
<div class="bottom"></div>
<div class="top"></div>
</body>
Используя Chrome Devtools для просмотра использования памяти этими двумя композитными слоями, я обнаружил, что:.bottom
Объем памяти составляет 39,1 КБ, а.top
Это 400 В, и разница очень заметна. Это потому что.top
— это слой композитинга, этап Composite, на котором находится преобразование, и теперь он полностью выполняется на графическом процессоре. Таким образом, для некоторых слоев со сплошным цветом мы можем использовать свойства ширины и высоты, чтобы уменьшить физический размер составного слоя, а затем использоватьtransform: scale(…)
Увеличьте масштаб, что может значительно снизить потребление памяти, вызванное композицией слоев.
Справочная статья
Аппаратное ускорение CSS3 тоже имеет свои недостатки.
Оптимизация производительности беспроводной сети: Композитный
CSS GPU Animation
Говоря о синтезе слоев
Если вы считаете, что этот контент ценен для вас, пожалуйста, поставьте лайк и подпишитесь на нашуОфициальный сайтА на нашем официальном аккаунте WeChat (WecTeam) каждую неделю публикуются качественные статьи: