Какие этапы отрисовки CSS существуют
Что проверяют
Понимаете ли вы, во что превращается CSS между загрузкой файла и пикселями, и можете ли по конкретному свойству сказать, какой этап оно перезапустит. Следом почти всегда идёт практический вопрос: почему анимировать transform дешевле, чем left.
Как отвечать
- парсинг и CSSOM: таблицы стилей разбираются в дерево правил. CSS блокирует рендер: пока стили из
<head>не загружены, страница не рисуется, иначе мелькнул бы голый HTML; - пересчёт стилей (Recalculate Style): для каждого узла DOM подбираются селекторы (движок сверяет их справа налево), применяются каскад, специфичность и наследование, получаются вычисленные значения;
- layout (reflow): считается геометрия боксов. Элемент с
display: noneв дерево раскладки не попадает, сvisibility: hiddenпопадает и занимает место; - paint: записываются команды отрисовки фонов, рамок, текста и теней в порядке контекстов наложения;
- растеризация и композитинг: команды превращаются в пиксели по слоям, слои собираются в кадр. В Chromium это делает отдельный поток композитора.
Главная практическая часть: изменение свойства перезапускает конвейер с определённого шага. width, top, font-size, padding запускают layout и всё после него. color, background, box-shadow обходятся перерисовкой. transform и opacity у элемента на своём слое затрагивают только композитинг, поэтому CSS-анимации на них плавные даже при занятом главном потоке.
Инструменты: вкладка Performance в DevTools показывает длительность Recalculate Style и Layout, режим Paint flashing подсвечивает перерисованные области. Для тяжёлых страниц есть contain и content-visibility: auto, они ограничивают объём пересчёта.
Где спотыкаются
Путают порядок и называют paint раньше layout. Нарисовать элемент, не зная его размеров и позиции, нельзя.
Вешают will-change на всё подряд. Каждый слой занимает память видеокарты, и на мобильных это ухудшает производительность, а не улучшает.
Не знают про принудительную синхронную раскладку: чтение offsetHeight или getBoundingClientRect() сразу после записи стилей в цикле заставляет браузер пересчитывать layout на каждой итерации.