Від стилівки до екрана: яке місце займає CSS у процесі роботи браузера
Від завантаження до пікселів: як створюються DOM, CSSOM та дерево відображення, де відбувається каскадування стилів та які джерела стилів конкурують за кожен елемент.
Більшість розробників пишуть CSS інтуїтивно: змінюють властивість, перезавантажують сторінку та перевіряють результат. Це працює доти, доки якась правило раптово відмовляється застосовуватися, сторінка відображає контент без стилів або „проста“ зміна стилю спричиняє проблеми з прокруткою. Кожна з цих проблем стає легшою для розуміння, як тільки ви дізнаєтесь, що насправді робить браузер між отриманням таблиці стилів та відображенням пікселів.
Цей посібник описує цей процес у загальних рисах. Ви дізнаєтесь, як браузер перетворює HTML на DOM, як таблиці стилів стають CSSOM, як ці елементи поєднуються у дерево відображення, де вирішуються суперечливі правила та які джерела стилів конкурують за кожен елемент. Це також поширене питання на співбесіді, зазвичай сформульоване як „як насправді працює CSS?“, і наведена нижче відповідь дає вам структурований спосіб на нього відповісти.
Перший крок: HTML стає DOM
Коли ви відкриваєте URL, браузер спочатку отримує HTML-документ. Він аналізує маркування зверху вниз, створюючи при цьому модель об’єктів документа. DOM — це дерево, яке представляє весь документ: кожен елемент є вузлом, а вузли пов’язані між собою як батьки, діти та брати/сестри, схоже на родовод. Усе, що описано в HTML, тепер знаходиться в цій структурі, і саме її читає та змінює JavaScript.
Аналіз відбувається поступово. Браузер не чекає на завантаження всього файлу, перш ніж почати створювати вузли, тому він може знаходити інші ресурси задовго до завершення завантаження документа.
Другий крок: таблиці стилів перетворюються на CSSOM
Під час парсингу HTML браузер знаходить таблиці стилів – чи то ті, що посилані за допомогою <link rel="stylesheet"> у розділі head, чи то вбудовані в елементи <style> – і починає їх також завантажувати та парсити. CSS під час обробки перетворюється на власну структуру у формі дерева – CSS Object Model, або CSSOM. Він виконує ту саму функцію щодо стилів, що й DOM щодо маркування.
Перетворення CSS на стилі, які можна використовувати для елемента, вимагає більше зусиль, ніж перетворення HTML на вузли. Особливо важливими є дві задачі:
- Вирішення конфліктів. Часто кілька декларацій стосуються однієї й тієї самої властивості одного елемента. Браузер вирішує ці конфлікти за допомогою алгоритму під назвою каскадування.
2em, 50% або inherit, що поки що не є чимось, що може використовувати двигун макетування. Браузер перетворює це на конкретні значення.Строго кажучи, CSSOM — це оброблена версія таблиць стилів, а каскадування та обчислення значень відбуваються під час того, як браузер розраховує стиль кожного елемента. Однак для уявлення достатньо думати про це як про «CSS обробляється, конфлікти вирішуються, значення узгоджуються, а результат приєднується до елементів».
Одна з практичних наслідків: оскільки браузер потребує стилів, щоб можна було відобразити щось зрозуміле, таблиці стилів у блоку head відкладають свою обробку до моменту завантаження та парсингу. Саме тому великі, повільні таблиці стилів затримують перше відображення контенту, і саме тому важливо зберігати критичні CSS-файли компактними для покращення продуктивності.
Третій крок: DOM та CSSOM об’єднуються у дерево відображення
Після того, як маркування оброблено у DOM, а стилі — у CSSOM, браузер об’єднує їх у дерево відображення. У цьому дереві містяться вузли, які будуть фактично відображатися, кожен з них поєднаний із своїми обчисленими стилями. Вузли, які не створюють візуального вихіду, такі як вміст <head> або елементи з параметром display: none, не враховуються.
На цьому етапі браузер знає, що потрібно намалювати та як форматовано кожну частину, але ще не знає, де саме вона розташуватиметься та якого буде розміру.
Четвертий крок: макетування та модель візуального форматування
Щоб перетворити стилізовані вузли на розташовані коробки, браузер дотримується того, що специфікації CSS називають моделлю візуального форматування. Ця частина специфікації CSS описує, як елементи дерева документа розміщуються на візуальних носіях, таких як екрани ноутбуків чи телефонів. Вона охоплює модель коробки, форматування блоків та вирівнювання в один ряд, плаваючі елементи, позиціонування та інші правила, які визначають розмір та положення кожної коробки.
Як тільки макетування обчислює геометрію кожної коробки, браузер їх намальовує, додаючи текст, кольори, рамки, зображення та тіні, і результат нарешті з’являється на екрані.
Весь процес у загальних рисах
Об’єднання цих етапів створює просту послідовність від маркапу до пікселів. Кожна стрілка приховує значну кількість роботи, але саме порядок має значення для аналізу помилок та продуктивності:
HTML
↓
DOM
↓
CSS
↓
CSSOM
↓
DOM + CSSOM
↓
Render Tree
↓
Layout
↓
Paint
↓
Pixels on the Screen
Реальні браузери поєднують ці кроки та додають ще більше етапів (наприклад, шари композиції), і зміна стилю пізніше може змусити браузер знову обчислювати стилі, переставляти елементи або перерисовувати вміст, залежно від конкретної властивості. Щоб детальніше дізнатися про ці витрати, перегляньте що коштує браузеру кожна зміна CSS.
Чому виникають конфлікти у деклараціях
Решта цього посібника присвятована першому з двох завдань обробки CSS: вирішенню конфліктів. Алгоритм, відповідальний за це, — каскадування. Він об’єднує всі таблиці стилів, які застосовуються до документа, і коли кілька оголошень встановлюють одну й ту саму властивість для одного елемента, вирішує, яке з них має перевагу.
Конфлікти є неминучими, і не лише тому, що ваша власна таблиця стилів може встановлювати значення color для посилання в двох місцях. Стилі надходять з кількох незалежних джерел, які називаються походженнями, і всі вони застосовуються до одних і тих самих елементів одночасно.
Стилі автора
Це оголошення, які пишете ви та ваша команда: ваші таблиці стилів, блоки <style> та атрибути style безпосередньо в коді. На більшості сайтів саме вони є найбільшим джерелом правил.
Стилі користувача
Людина, яка переглядає сторінку, також може впливати на стилі. Браузери дозволяють користувачам налаштовувати параметри, такі як стандартний розмір шрифту, а деякі з них підтримують також власні таблиці стилів користувача чи розширення, які їх впроваджують. Ці налаштування є особливо важливими для доступності, оскільки вони дозволяють людям із слабким зором або труднощами у читанні пристосувати сторінку до своїх потреб.
Стилі користувацького агента
Нарешті, браузер (користувацький агент) постачає власну стандартну таблицю стилів. Саме тому елемент <a> без стилів виглядає синім та підкресленим, заголовки є жирними та більшими за текст основної частини сторінки, а елемент <body> має невеликий відступ. Ці стандарти називаються стилями користувацького агента.
Коли каскадне поєднання об’єднує всі три джерела стилів, одна й та сама властивість у одному елементі може легко отримувати кілька суперечливих значень, і браузеру потрібен детермінований спосіб вибору.
Як вирішує каскад
Каскад порівнює суперечливі оголошення за фіксованою послідовністю критеріїв, переходячи до наступного лише тоді, коли попередній призводить до рівності:
- Походження та важливість. Звідки походить оголошення та чи позначене воно як
!important. - Специфічність. Наскільки точно селектор націлений на елемент; селектор ID має перевагу над селектором класу, який у свою чергу має перевагу над селектором типу.
- Порядок джерела. Якщо все інше однакове, перемагає оголошення, яке з’являється пізніше.
Ранжування джерел
Для першого критерію класичний порядок пріоритету йде від найвищого до найнижчого наступним чином:
- Оголошення користувача, позначені як
!important. - Оголошення автора, позначені як
!important. - Звичайні оголошення автора.
Зверніть увагу на значення цього. Ваші звичайні стилі переважають над звичайними налаштуваннями користувача та стандартними параметрами браузера, саме це дозволяє створювати веб-сторінки. Але !important змінює порядок пріоритетів між користувачами та авторами: користувач, якому справді потрібний більший шрифт або вища контрастність, може позначити це бажання як важливе та проігнорувати навіть ваші правила !important. Стандартні параметри браузера залишаються на останньому місці та застосовуються лише тоді, коли ніхто інший нічого не вказав.
Сучасний CSS удосконалює цю схему. Чинна каскадна система також враховує шари каскадування (@layer), стилі, встановлені під час анімацій та переходів, а також декларації !important для user-agent, які мають вищий пріоритет за всі інші важливі декларації. Вищений спрощений перелік все ще відображає найважливіші зв’язки у повсякденній практиці; для отримання повного порядку перегляньте посилання на довідник каскадування MDN, наведене раніше.
Специфічність та порядок джерел заслуговують на окреме детальне розглядання, включаючи те, як порівнюються ваги селекторів, та чому !important так часто створює більше проблем, ніж їх вирішує. Це розглядається у статті як каскадування обирає переможця.
Чому ці знання є корисними
Розуміння цього процесу змінює спосіб виправлення помилок та написання стилів:
- Правила, які не застосовуються, — це майже завжди каскадні втрати. Знання порядку походження, специфічності та послідовності джерел допомагає знайти правильне рішення замість використання
!important. - Миттєві прояви нестилізованого або пізно стилізованого контенту виникають через блокування відображення стилевих таблиць та через стилі, які надходять після першого відображення.
- Проблемні взаємодії часто пов’язані зі змінами, які змушують систему знову обробляти макет чи відображення, що можна уникнути, якщо знати, на якому етапі діє та чи інша властивість.
- Керований CSS — це CSS із низькою, прогнозованою специфічністю та чіткою послідовністю джерел, що полегшує обробку як браузером, так і колегами.
Підсумок
Браузер перетворює HTML на DOM, таблиці стилів — на CSSOM, поєднує їх у дерево відображення з видимими, стилізованими вузлами, а потім використовує модель візуального форматування для розташування елементів перед їх намальовуванням. На етапі обробки CSS першим бар’єром є механізм каскадування стилів: він об’єднує стилі автора, користувача та user-agent та вирішує кожен конфлікт спочатку за походженням та важливістю, потім за специфічністю, а нарешті — за порядком джерел. Наступний етап, під час якого переможні значення перетворюються на конкретні числа, які може використовувати двигун розташування, пояснюється у як браузери вирішують значення CSS перед розташуванням елементів.