awesome-everything EN
↑ Обратно к восхождению

Браузер и фронтенд-рантайм

Слои композитора: продвижение, перекрытие и память GPU

Суть Как элементы попадают в слои композитора, почему один transform может утащить за собой дюжину соседей, и во сколько обходится слой в памяти GPU.
Высота — путь к senior
НольJuniorMiddleSenior
Ты на middle-высоте — в небе
◷ 14 min

Вы добавляете will-change: transform одной карточке в списке — чтобы анимация ховера была плавной. Панель Layer Borders в DevTools загорается сорока цветными рамками, о которых вы не просили. Браузер повысил соседей, потому что не мог иначе.

Как элементы попадают к композитору

Одни элементы получают собственный слой композитора:

  • transform: translate3d(...) и любой 3D-transform
  • will-change: transform (или любое компонуемое свойство)
  • position: fixed
  • <video>, <canvas>
  • Анимируемый прямо сейчас opacity
  • filter: blur(...) и другие графические фильтры
  • Изолированные stacking-контексты, перекрывающие другой слой

Каждый слой растеризуется один раз (отрисовка), загружается в GPU, а потом дёшево рекомпонуется следующие тысячи кадров. Анимировать transform слоя «бесплатно» — главный поток может спать. Анимировать его top дорого — главный поток пересчитывает мир каждый кадр.

Жизненный цикл слоя

1. Элемент получает триггер продвижения (transform3d, will-change и т.д.)
2. Браузер рисует пиксели элемента в GPU-bitmap (разовая цена)
3. Композитор перемещает/смешивает bitmap каждый кадр — главный поток не участвует
4. Память GPU держит bitmap, пока слой не уничтожится (элемент удалён или триггер снят)

Правило перекрытия: слои, которых вы не просили

Композитор обязан сохранять визуальную корректность. Если элемент A — слой (скажем, с transform) и элемент B рисуется поверх A в document order без собственного слоя, композитор не сможет разрешить их z-стек: слой A окажется поверх B, хотя B должен быть выше.

Браузер решает это, повышая B до собственного слоя, нередко утащив за собой соседние элементы. Затем компоzитор сжимает соседние неанимируемые слои в общий «squashed»-слой, чтобы ограничить взрыв, но эвристика несовершенна.

Один невинный will-change: transform на карточке в середине ленты может повысить дюжину соседей.

Используйте Rendering-панель DevTools → «Layer Borders», чтобы видеть, что повышено. Обращайте внимание на слои с метками «compositor-induced» или «overlap» — они пробрались без вашего ведома.

will-change как обоюдоострое оружие

will-change: transform — подсказка браузеру: «Я скоро анимирую это свойство, заранее подготовь bitmap, чтобы композитор мог двигать его, не возвращаясь к компоновке или отрисовке». Браузер немедленно повышает элемент.

Цена: память GPU — ширина × высота × 4 байта на слой.

Анти-паттерн will-change: will-change: transform на каждом компоненте в дизайн-системе постоянно резервирует слой для каждого экземпляра. В списке из 100 карточек с 5 элементами с will-change каждая — страница держит 500 слоёв, возможно, сотни МБ памяти GPU. На телефоне с 256 МБ GPU-памяти ОС начинает вытеснять; браузер растеризует повторно на лету, и страница заикается сильнее, чем без слоёв.

Лечение: устанавливайте will-change непосредственно перед началом анимации (например, на mouseenter) и убирайте на animationend. Относитесь к нему как к сигналу «вперёд», а не постоянной настройке.

Граничные случаи

Правило перекрытия взаимодействует со stacking-контекстами z-index неочевидным образом. Элемент с z-index: 1 и position: relative создаёт изолированный stacking-контекст. Если этот контекст перекрывает слой композитора, вся его закрашенная область должна быть повышена, чтобы избежать межслоевого кровотечения. Вот почему добавление position: relative; z-index: 1 к всплывающей подсказке над анимированным фоном может вызвать полностраничный каскад слоёв в сложных layouts. Решение — держать повышаемые элементы (анимируемые, fixed, video) в отдельном stacking-контексте от непродвигаемых соседей, или использовать isolation: isolate явно, чтобы ограничить эффекты stacking-контекста.

Закончи аналогию

В метафоре кухни слой — это готовая тарелка, стоящая на раздаче: уже приготовлена, готова для раздатчика. Какое CSS-свойство превращает обычный элемент в такую «предварительно приготовленную тарелку», чтобы композитор мог перемещать её без повторной готовки?

Посчитай

Элемент 1920 × 1080 продвинут в собственный слой композитора. Каждый пиксель — 4 байта (RGBA). Сколько мегабайт GPU-памяти занимает этот единственный слой?

МБ
Викторина

Команда добавляет `will-change: transform` каждой карточке в дизайн-системе. GPU-память на мобильном раздувается. Каков механизм?

Викторина

Элемент A имеет `will-change: transform`. Элемент B перекрывает A в document order. У элемента B нет триггера продвижения. Что делает браузер?

Вспомните перед уходом
  1. 01
    Какова цена GPU-памяти слоя compositor 1920×1080?
  2. 02
    Почему `will-change: transform` на одном элементе иногда продвигает соседей?
  3. 03
    Каков правильный паттерн использования `will-change`?
Итог

Слой compositor — GPU-bitmap, который compositor может позиционировать и смешивать дёшево каждый кадр, не трогая главный поток. Триггеры продвижения: 3D-трансформы, will-change, position: fixed, video, canvas и анимируемый opacity. Правило перекрытия вынуждает браузер продвигать элементы, перекрывающие слой — один will-change в списке может вызвать дюжину неявных продвижений. Каждый полноэкранный слой стоит ~7,91 МБ GPU-памяти; исчерпание мобильных GPU-бюджетов вызывает вытеснение тайлов и повторную растеризацию, создавая худший jank, чем без слоёв вообще. Правильный паттерн — ограничивать will-change длительностью анимации. Layer Borders в DevTools визуализирует каждый продвинутый элемент и его причину.

Связанные уроки
встречается в162
Продолжить восхождение ↑Флейм-стрип DevTools и жизненный цикл кадра
хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.