Как 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>, встроенные атрибуты стиля, <style> блоки в голове и разные механизмы рендеринга?
  • Блокирует ли загрузка содержимого CSS загрузку самого HTML-документа?

person Wesley Murch    schedule 05.08.2011    source источник
comment
Один пример того, почему меня это волнует: я создаю уменьшенный файл CSS из 10-15 небольших файлов. Все находится в пространстве имен или использует достаточно специфические селекторы, где во многих случаях порядок можно поменять местами. Я всегда добавляю наименее релевантные элементы CSS в последнюю очередь, полагая, что стили будут применяться последними, а если они будут первыми, то будут оцениваться более важные вещи (например, макет страницы или общие классы). позже. У меня очень сильное чувство, что это совершенно не имеет значения, но я ищу факты, подтверждающие это. Ответ на это должен также ответить на связанный вопрос.   -  person Wesley Murch    schedule 05.08.2011


Ответы (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.

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

person Matt Ball    schedule 05.08.2011
comment
Я думаю, что хорошо понимаю, как на перерисовку влияет новый HTML-код, загружаемый в браузер, и я недавно прочитал эту статью, но я думаю, что это не совсем то, что я после, или это? Почему мой тест не прошел? Тег <html> существовал до того, как был применен какой-либо CSS, верно? Так почему же содержимое таблицы стилей не применялось постепенно (сначала зеленый, затем красный)? Я пытаюсь быть кратким, но у меня много вопросов. В моем тесте не было буквально никакого контента, кроме минимального количества тегов для создания демо. Прав я был или нет в другом посте? - person Wesley Murch; 05.08.2011
comment
Смотрите мое редактирование (в самом низу вопроса). Извините, что ввалил весь этот пост в блоге... который вы уже читали. Тем не менее, я думаю, что это уместно, если другие не читали его, и я стараюсь делать свои ответы как можно более автономными. - person Matt Ball; 05.08.2011
comment
Нет, это здорово, чувак, и кажется, ты пришел к тому же выводу, что и я, но с неопределенностью. Позвольте мне спросить вас из любопытства: до того, как вы услышали мои результаты, чего вы ожидали от теста, который я провел? Я вернусь утром, чтобы проголосовать, дать пять и еще много чего, мне нужно было ответить на этот вопрос, прежде чем меня поглотит что-то другое, но банкомат меня утомил. - person Wesley Murch; 05.08.2011
comment
Если подумать, последовательно загружаются только внешние скрипты. Другие ресурсы можно загружать параллельно. Я думаю, что браузер просто анализирует всю таблицу стилей по мере загрузки, но не применяет стиль до тех пор, пока не будет проанализирован весь файл. (Да, мне тоже нужно лечь в мешок...) - person Matt Ball; 05.08.2011

Первое и самое важное, что нужно понять, это то, что браузеры не могут начать отрисовку страницы до тех пор, пока не будет загружен весь 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 Алекс Рассел в течение 36 минут подробно рассказывает о том, как webkit анализирует CSS, как работают перекомпоновки и перерисовки и что их запускает.

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

person Moses    schedule 05.08.2011
comment
Очень интересное видео, но я не нашел то, что искал, хотя выделенный вами раздел хорошо объясняет специфику селектора CSS. Чтобы было ясно, я не спрашиваю, как сделать вещи быстрее, а скорее для объяснения того, как/когда стили CSS на самом деле применяются или как они передаются в браузер или механизм рендеринга из таблицы стилей. Ваш ответ: Downloads all CSS, then begins painting the document from the top-down. звучит правильно, но я не могу найти никаких ссылок или фактов, подтверждающих или опровергающих это, кроме моих собственных (возможно, ошибочных) экспериментов. - person Wesley Murch; 05.08.2011
comment
@Wesley Уэсли Я действительно ответил на ваш вопрос о том, как и когда применяются стили. Стили применяются к элементам DOM сверху вниз, поскольку HTML воспринимается как поток. Более конкретно, для каждого элемента, который видит браузер, он проверяет таблицу стилей на возможные совпадения CSS (он читает CSS справа/слева), а затем применяет применимые стили (КАК). Они не вступают в силу до тех пор, пока не будут загружены все css, и именно тогда браузер начинает рисовать страницу (КОГДА). В двух моих ссылках, а также в ссылке snook.ca от Мэтта представленные факты действительно подтверждают это. - person Moses; 05.08.2011
comment
Конкретная часть, для которой я ищу ссылку: They do not take effect until all css is downloaded. Это зависит от движка рендеринга или просто так работает? В моем тесте (который, кажется, подтверждает ваши утверждения), <html> был единственным тегом с правилами CSS и был введен не после загрузки CSS, а до (если вы не говорите, что закрывающий тег был необходим для обнаружения элемента ). Тест также провалился со встроенным style в теге html, что было интересно и неожиданно. Кроме того, интересно, блокирует ли загрузка CSS HTML или нет. - person Wesley Murch; 05.08.2011
comment
@Wesley re: что загружается параллельно, а что нет: это сложно . - person Matt Ball; 05.08.2011
comment
@Matt: Будучи внимательным к скорости страницы и yslow, я знал о пунктах в этом видео о том, как <script> блокирует другие внешние ресурсы, но я считаю, что этот вопрос совсем о другом. Например, почему мой тест не работал, когда я использовал два отдельных тега <link> в голове? Мой вопрос неясен или глуп? Ответ прямо здесь, но просто не доходит до меня? Посмотрите мой пример, в комментарии, который я разместил по самому вопросу, я думаю, что он ясно объясняет один аспект моих опасений. - person Wesley Murch; 05.08.2011

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

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

Обобщить:

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

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

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

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

person Pragatheeswaran    schedule 12.06.2015
comment
Также загляните на этот сайт. html5rocks.com/en/tutorials/internals/howbrowserswork - person Pragatheeswaran; 12.06.2015
comment
Я думаю, что ОП спросил о том, как будут применяться стили css, а не о порядке рендеринга html-страницы. - person Kira; 20.01.2016
comment
Для CSS было бы невозможно заблокировать уже запрошенный HTML скачать - вопрос в том, заблокирован ли синтаксический анализ/рендеринг. И обратите внимание: в документе, на который вы ссылаетесь, говорится, что последовательность, которую вы суммируете, является упрощением — многое происходит параллельно: Для лучшего взаимодействия с пользователем механизм рендеринга попытается отобразить содержимое на экране, как только насколько это возможно. Он не будет ждать, пока весь HTML будет проанализирован, прежде чем начать построение и компоновку дерева рендеринга. Части содержимого будут проанализированы и отображены, в то время как процесс продолжится с остальным содержимым, которое продолжает поступать из сети. - person ToolmakerSteve; 30.04.2019