Главная / Статьи / От шаблона стилей к экрану: какова роль CSS в работе браузера

От шаблона стилей к экрану: какова роль CSS в работе браузера

От загрузки CSS до пикселей: как формируются DOM, CSSOM и дерево отрисовки, где происходит каскадирование стилей и какие источники стилей конкурируют за каждый элемент.

1733 слов

Большинство разработчиков пишут 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 в узлы. Выделяются два основных этапа:

  1. Урегулирование конфликтов. Часто несколько объявлений касаются одного и того же свойства у одного и того же элемента. Браузер разрешает эти конфликты с помощью алгоритма, называемого каскадированием.
  • Обработка окончательных значений. В описании победителя может быть указано 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> есть небольшой отступ. Эти стандарты называются стилями пользовательского агента.

    Когда каскадное объединение сливает все три источника стилей, одно и то же свойство у одного и того же элемента может легко получить несколько конкурирующих значений, и браузеру требуется определенный способ для выбора.

    Как принимается решение каскадом

    Каскад сравнивает противоречащие друг другу объявления с использованием фиксированной последовательности критериев, переходя к следующему только тогда, когда предыдущий приводит к равенству:

    1. Происхождение и важность. Откуда поступило объявление и отмечено ли оно как !important.
    2. Специфичность. Насколько точно селектор нацелен на элемент; селектор по ID имеет приоритет перед селектором класса, который в свою очередь имеет приоритет перед селектором типа.
    3. Порядок источника. Если все остальные параметры одинаковы, побеждает объявление, появившееся позже.

    Ранжирование источников

    Что касается первого критерия, то классический порядок приоритетов идет от высшего к низшему следующим образом:

    1. Объявления пользователя с пометкой !important.
    2. Объявления автора с пометкой !important.
    3. Обычные объявления автора.
  • Обычные объявления пользователей.
  • Объявления User-Agent (стандартные настройки браузера).
  • Обратите внимание на значение этого. Ваши стандартные стили переопределяют обычные предпочтения пользователя и стандартные настройки браузера, что и позволяет создавать страницы. Однако использование !important меняет порядок приоритетов между пользователями и авторами: пользователь, которому действительно нужен более крупный шрифт или выше контрастность, может отметить такое предпочтение как важное, тем самым преодолев даже ваши правила !important. Собственные стандартные настройки браузера оказываются в самом конце и применяются только тогда, когда никто другой не указал иных настроек.

    Современный CSS усовершенствует эту схему. Текущая каскадная система также учитывает уровни каскадирования (@layer), стили, задаваемые анимациями и переходами, а также декларации !important для user-agent, которые имеют приоритет над всеми другими важными декларациями. Упрощенный список выше всё ещё отражает наиболее важные аспекты повседневной работы; для полного порядка сравнения обратитесь к ссылке на руководство MDN о каскадировании, приведённой ранее.

    Специфичность и порядок источников заслуживают отдельного подробного рассмотрения, включая способы сравнения весов селекторов и причины, по которым !important часто создаёт больше проблем, чем решает. Об этом говорится в статье как каскадирование выбирает победителя.

    Почему эти знания полезны

    Понимание процесса каскадирования меняет подход к отладке и написанию стилей:

    • Правила, которые не применяются, почти всегда связаны с каскадными потерями. Знание порядка происхождения, специфичности и порядка источников помогает определить, где искать решение, вместо того чтобы использовать !important.
    • Моменты отображения нестилизованного или поздно стилизованного контента возникают из-за того, что таблицы стилей могут блокировать отрисовку, а также из-за стилей, которые приходят после первой отрисовки.
    • Проблемные интеракции часто связаны с изменениями, которые заставляют снова выполняться операции по формированию макета или отрисовке, чего можно избежать, если знать, на каком этапе влияет та или иная свойство.
    • Удобный для обслуживания CSS — это CSS с низкой, предсказуемой специфичностью и четким порядком источников, что упрощает обработку как браузером, так и коллегами.

    Заключение

    Браузер преобразует HTML в DOM, таблицы стилей — в CSSOM, объединяет их в дерево отрисовки из видимых, оформленных узлов, а затем использует модель визуального форматирования для расположения элементов перед их отрисовкой. На этапе обработки CSS первым фильтром выступает механизм каскадирования стилей: он объединяет стили автора, пользователя и пользовательского агента и разрешает все конфликты сначала по источнику, затем по степени важности, а потом по специфичности. Следующий этап, при котором победившие значения преобразуются в конкретные числа, используемые движком макетирования, описан в статье о том, как браузеры разрешают значения CSS перед макетированием.