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

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

Инвалидация, dirty-биты и contain

Суть Как изменения CSS-свойств распространяются через пайплайн, что контролирует радиус взрыва, и как contain/content-visibility изолируют ущерб.
Высота — путь к senior
НольJuniorMiddleSenior
Ты на middle-высоте — в небе
◷ 14 min

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

Правило инвалидации

Изменение CSS-свойства инвалидирует одну или несколько стадий пайплайна. Всё начиная с этой стадии и ниже перезапускается.

Изменение CSSИнвалидируетЦена
width, height, top, leftКомпоновку (+ отрисовку + композитинг)Высокая
background-color, colorОтрисовку (+ композитинг)Средняя
transform, opacity (на собственном слое)Только композитингНизкая
filter: blur(...)Отрисовку (+ композитинг)Средняя–Высокая

csstriggers.com публикует карту по свойствам. Выучите дешёвые (transform, opacity, filter на продвинутом элементе) и дорогие (всё, что влияет на flow).

Как распространяются dirty-биты

Правила распространения dirty-битов

  • Style-флаги текут вниз по DOM-дереву — смена класса на родителе делает dirty всех потомков, чьи селекторы матчатся.
  • Layout-флаги — по box-дереву — изменение width у родителя может сделать dirty сиблингов, если их позиция зависит от него.
  • Paint-флаги ограничены paint-слоем — paint-меняющее изменение инвалидирует bitmap этого слоя; сиблинг-слои со своими bitmap-ами не затрагиваются.
  • Композитинг всегда dirt-free — работает с уже растеризованными тайлами, лишь перезапускает GPU draw call.

Правило: dirty-биты текут ВНИЗ по графу зависимостей, никогда вверх.

Если удаётся изолировать изменения в независимом поддереве, инвалидация останавливается на границе изоляции.

CSS Containment: ограничение радиуса взрыва

CSS Containment даёт ручку, ограничивающую распространение инвалидации.

  • contain: layout — «компоновка этого элемента не может затронуть предков». Если ребёнок ресайзится, сиблинги родителя не нужно перекомпоновывать.
  • contain: paint — отрисовка ограничена коробкой (переполнение клипуется). Браузер может пропустить отрисовку, когда элемент за экраном.
  • contain: strict — комбинирует layout, paint и size containment.

Более новое content-visibility: auto идёт дальше: говорит браузеру пропустить элемент полностью (без пересчёта стилей, без компоновки, без отрисовки), когда он за экраном. В паре с contain-intrinsic-size (даёт браузеру placeholder-размер) это позволяет странице с тысячами элементов ниже первого экрана рендериться за миллисекунды — только видимые элементы платят цену.

Это современные «бесплатные победы» для страниц с длинными списками, infinite scroll-лентами и длинным контентом.

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

Шрифты и FOIT/FOUT. Веб-шрифт — это входной байт для пайплайна, который часто упускают. Шрифт начинает грузиться, когда CSS-парсер видит font-family, использующий @font-face с src. Пока шрифт не пришёл, браузер либо показывает текст шрифтом-фоллбэком (FOUT, flash of unstyled text), либо прячет текст (FOIT, flash of invisible text). Свойство font-display управляет этим: swap — фоллбэк сразу, потом сменить; optional — фоллбэк, если шрифт не успел за ~100 мс; block — спрятать до 3 секунд. При смене шрифта на загруженный браузер запускает пересчёт стилей и компоновку, потому что метрики шрифта меняют ширину текста. На большом текстовом блоке эта смена видна как кадровый jank через 200–500 мс после первой отрисовки.

Изображения и CLS. Изображение без указанной ширины и высоты форсирует перекомпоновку, как только грузится: коробка была 0×0, стала фактическим размером, всё вокруг сдвигается — главная причина CLS-регрессий. Лечение — задавать explicit width/height в HTML или aspect-ratio в CSS; браузер резервирует место заранее, и загрузка изображения становится только paint-инвалидацией. Современное loading="lazy" грузит off-screen изображения лениво, но всё равно нужны заранее заданные размеры, иначе layout shift в момент попадания во viewport.

Викторина

Какое изменение свойства инвалидирует только стадию композитинга (без компоновки, без отрисовки)?

Викторина

Вы добавляете `contain: layout` к компоненту-карточке. Дочерний элемент внутри неё меняет размер. Какие элементы нужно перекомпоновывать?

Викторина

Страница использует `content-visibility: auto` на 10 000 элементов списка ниже первого экрана. Что происходит при первой отрисовке?

Вспомните перед уходом
  1. 01
    Какие стадии пайплайна инвалидирует изменение `width`?
  2. 02
    Что говорит браузеру `contain: layout`?
  3. 03
    Каков механизм `content-visibility: auto`?
Итог

Каждое изменение CSS-свойства инвалидирует ровно одну или несколько стадий пайплайна; dirty-биты текут вниз. width инвалидирует компоновку, которая форсирует отрисовку и композитинг. opacity на продвинутом элементе инвалидирует только композитинг — поэтому он «бесплатный». CSS Containment (contain: layout, contain: strict) останавливает взрыв инвалидации на границе. content-visibility: auto идёт дальше: off-screen поддеревья полностью пропускаются (display-locked), превращая отрисовку 1200 мс в 10 мс для длинных страниц. Изображения без объявленных размеров вызывают layout-инвалидацию при загрузке — это корневая причина большинства CLS-регрессий. Смена шрифта при загрузке вызывает пересчёт стилей и компоновку из-за смены метрик текста.

Связанные уроки
встречается в162
Продолжить восхождение ↑Слои композитора: продвижение, перекрытие и память GPU
хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources4
expand
  1. 01
  2. 02
  3. 03
  4. 04

Trademarks belong to their respective owners. Editorial reference only.