Как CSS применяется браузером и влияет ли это на перерисовку?

Допустим, у нас есть HTML-страница с одной таблицей стилей <link>, Как браузер берет правила в этой таблице стилей и применяет их к HTML? Я не спрашиваю о том, как сделать это быстрее, я хочу знать, как обрабатывается сам рендеринг.

Применяет ли оно каждое правило одно за другим, когда оно анализирует таблицу стилей и постепенно отображает результат? Или содержимое файла CSS полностью загружено, затем полностью оценено, а затем применено к HTML сразу? Или что-то другое?

Я спрашиваю об этом после публикации ранее ответа на вопрос о том, как порядок правил CSS влияет на скорость рендеринга, при условии, что стили были отрисованы при загрузке таблицы стилей, поэтому первые правила будут применяться перед последними, а не все сразу. Я не уверен, где я взял идею, это просто то, что я всегда думал.

Я попробовал демо на моем сервере, которое выглядело так:

<!DOCTYPE html>
<html>
<head>
   <title>Test</title>
   <link rel="stylesheet" href="test.css" />
</head>
<body></body>
</html>

test.css содержание:

html { background:green }
/* thousands of lines of irrelevant CSS to make the download slow */
html { background:red }

При тестировании в Firefox 5 я ожидал сначала увидеть зеленый, а затем - красный. Этого не случилось Я попытался с двумя отдельными таблицами стилей с противоречивыми правилами и получил те же результаты. После многих комбинаций единственный способ заставить его работать - встроенный <style> блок в <head> с противоречивыми правилами, исходящими от <link> в <body> (само тело было полностью пустым, за исключением тега ссылки). Даже используя встроенный style атрибут на <html> тег, а затем загрузка этой таблицы стилей не создали мерцание, которое я ожидал.

Влияет ли перерисовка каким-либо образом на CSS или окончательный результат применяется сразу после загрузки всей таблицы стилей, и его правила вычисляются в соответствии с тем, каким должен быть конечный результат? Файлы CSS загружаются параллельно с самим HTML или блокируют его (как это делают теги скрипта)? Как это на самом деле работает?

Я не ищу советы по оптимизации, я ищу авторитетные ссылки на эту тему, чтобы я мог ссылаться на них в будущем. Было очень трудно найти эту информацию, не найдя тонны несвязанного материала. Резюме:

  • Загружается ли весь контент CSS перед его применением? (ссылка пожалуйста)
  • Как на это влияют такие вещи, как @import несколько <link> s, встроенные атрибуты стиля, <style> блоки в голове и разные движки рендеринга?
  • Блокирует ли загрузка содержимого CSS саму загрузку HTML-документа?

3 ответа

Решение

Как браузер берет правила в этой таблице стилей и применяет их к HTML?

Обычно это делается в потоковом режиме. Браузер считывает теги HTML как поток и применяет все возможные правила к элементам, которые он видел до сих пор. (Очевидно, это упрощение.)

Интересные вопросы и ответы: используйте CSS-селекторы для сбора HTML-элементов из потокового парсера (например, потока SAX) (отвлечение внимания при поиске статьи, которую я имею в виду).


Ах, вот оно: почему у нас нет родительского селектора.

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

Взгляните на тело примера документа:

<body>
   <div id="content">
      <div class="module intro">
         <p>Lorem Ipsum</p>
      </div>
      <div class="module">
         <p>Lorem Ipsum</p>
         <p>Lorem Ipsum</p>
         <p>Lorem Ipsum <span>Test</span></p>
      </div>
   </div>
</body>

Браузер запускается сверху и видит body элемент. На данный момент, он думает, что он пуст. Он не оценил ничего другого. Браузер определит, что такое вычисляемые стили, и применит их к элементу. Какой шрифт, цвет, высота строки? После того, как он это выясняет, он рисует его на экране.

Далее он видит div элемент с идентификатором content, Опять же, на данный момент, он думает, что он пуст. Он не оценил ничего другого. Браузер выясняет стили, а затем div красится. Браузер определит, нужно ли перекрашивать тело - элемент стал шире или выше? (Я подозреваю, что есть и другие соображения, но изменения ширины и высоты являются наиболее распространенными эффектами, которые дочерние элементы оказывают на своих родителей.)

Этот процесс продолжается до тех пор, пока не достигнет конца документа.

CSS оценивается справа налево.

Чтобы определить, применимо ли правило CSS к определенному элементу, оно начинается справа от правила и работает влево.

Если у вас есть правило, как body div#content p { color: #003366; } затем для каждого элемента, когда он отображается на странице, он сначала спросит, является ли он элементом абзаца. Если это так, он будет работать в DOM и спросит, div с идентификатором контента. Если он найдет то, что ищет, он продолжит свой путь вверх по DOM, пока не достигнет body,

Работая справа налево, браузер может определить, применяется ли правило к этому конкретному элементу, который он пытается нарисовать в окне просмотра намного быстрее. Чтобы определить, какое правило более или менее эффективно, необходимо выяснить, сколько узлов необходимо оценить, чтобы определить, можно ли применить стиль к элементу.


Так почему же содержимое таблицы стилей не применялось постепенно (сначала зеленым, а затем красным)?

Я думаю, что ответ заключается в том, что внешние таблицы стилей анализируются по мере их загрузки, но не применяются до тех пор, пока не будет проанализирована вся таблица стилей. Конечно, при разборе таблицы стилей браузер оптимизирует ненужные и избыточные правила CSS.

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

Первая и самая важная вещь, которую нужно понять, это то, что браузеры не могут начать рисовать страницу, пока не будет загружен весь CSS. (Имейте в виду, спецификация W3C гласит, что CSS-ссылки разрешены только в заголовке, поэтому, когда вы начнете ссылаться на таблицы стилей в теге body, как вы это делали, разные браузеры будут обрабатывать эту ситуацию по-разному.)

Теперь веб-страница читается как поток, и правила CSS применяются к элементам HTML по мере их поступления на страницу. Чтобы процитировать статью Google, связанную ниже:

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

Итак, чтобы ответить на ваши вопросы:

Применяет ли оно каждое правило одно за другим, когда оно анализирует таблицу стилей и постепенно отображает результат? Или содержимое файла CSS полностью загружено, затем полностью оценено, а затем применено к HTML сразу? Или что-то другое?

Загружает весь CSS, затем начинает рисовать документ сверху вниз.

При тестировании в Firefox 5 я ожидал сначала увидеть зеленый, а затем - красный. Этого не случилось Я попытался с двумя отдельными таблицами стилей с противоречивыми правилами и получил те же результаты.

Это потому, что сначала загружается весь CSS, затем, когда он встретил ваш элемент, он применил только красный стиль из-за того, как работает каскад.

После многих комбинаций единственный способ заставить его работать - встроенный <style> блок в <head>с противоречивыми правилами, исходящими от <link> в <body>

Хотя я не могу точно сказать, почему это произошло, я представляю, что браузер не искал CSS в теге body, начал рисовать, столкнулся с CSS body, а затем перекрасил.

На перерисовку влияет каким-либо образом CSS?

Честно говоря, я бы больше беспокоился о том, что JS вызвал перекрашивание. Но если у вас очень большой DOM, имеет смысл структурировать ваш CSS таким образом, чтобы вы не вызывали рефлоки из-за странного позиционирования. @Matt дал вам несколько хороших ссылок на эту тему. Некоторые хорошие ресурсы:

http://www.dayofjs.com/videos/22158462/web-browsers_alex-russel Алекс Рассел подробно рассказывает о том, как webkit выполняет синтаксический анализ CSS, как работает перекомпоновка и перерисовка, и что их запускает.

http://code.google.com/speed/page-speed/docs/rendering.html Это базовая статья о том, как оптимизировать CSS-рендеринг.

Я не уверен насчет помеченного ответа. Я сомневаюсь, что это правильно. По этой ссылке от Google Developers браузер сначала загружает файл HTML, и когда он видит файл CSS, связанный с внешним ресурсом, он начинает загружать файл CSS, в то же время одновременно создавая структуру DOM для данного файла HTML, так как CSS не повлияет ДОМ. Обратите внимание, что он не применяет никаких стилей к документу, когда браузер загружает файл CSS.

После загрузки файла CSS (предположим, что нет файлов сценариев) и, если построение DOM завершено, браузер начинает сопоставлять свойства CSS с этими узлами в дереве DOM. После этого он создает другое дерево под названием Render tree, которое строит все объекты, которые должны отображаться, в виде прямоугольников. Только после завершения рендеринга дерево начинает рисовать на экране.

Подвести итоги:

  • Браузер полностью загружает файл CSS.
  • Браузер не применяет стили к странице при загрузке. Только после завершения загрузки начинается сопоставление правил.
  • Правила применяются только на этапе построения дерева рендеринга.
  • Загрузка файла CSS не блокирует загрузку HTML. Вы должны отметить, что браузер

Сначала загружаются все html-файлы, а затем загружаются файлы стилей и скриптов.

Вы можете использовать консоль разработчика Chrome, чтобы проверить их. Используйте вкладку шкалы времени, чтобы увидеть все это.

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

Другие вопросы по тегам