How Do Browsers Parse/Render CSS

How do browsers read and interpret CSS?

If you've worked with a slow connection anytime recently, you'll find that CSS will be applied to elements as they (slowly) appear, actually reflowing page content as the DOM structure loads. Since CSS is not a programming language, it doesn't rely on objects being available at a given time to be parsed properly (JavaScript), and the browser is able to simply re-assess the structure of the page as it retrieves more HTML by applying styles to new elements.

Perhaps this is why, even today, the bottleneck of Mobile Safari isn't the 3G connection at all times, but it is the page rendering.

what happens to the rendering engine in chrome when the browser download CSS files?

The following happens in Chromium:

CSS files, like any other files loaded through a <link> element won't affect the parser. The parser will continue and simultaneously send out a GET request to fetch the requested source.
The CSS is parsed by the main thread, but this is done after the HTML is parsed.

Do browsers parse CSS on CSS file loading?

CSS is, along with HTML, a render blocking resource. Browsers need it to construct the render tree. So yes, it is converted into CSSOM right after it's downloaded.

There are some cases in which the CSS is not parsed right away, for example if they are added as a print stylesheet: <link href="print.css" rel="stylesheet" media="print">. In that case they will be parsed only if the page is printed.

You can actually try for yourself if you are using Chrome Developer Tools.

Sample Image

The red line represents the Load event, that's when all elements have been downloaded and parsed. The dark green section is when the CSS has been parsed and is just waiting for other resoures to load.

For more information:

  • https://developers.google.com/web/fundamentals/performance/critical-rendering-path/render-blocking-css
  • https://developers.google.com/web/fundamentals/performance/critical-rendering-path/constructing-the-object-model
  • https://developers.google.com/web/fundamentals/performance/critical-rendering-path/analyzing-crp

How do browsers parse/render CSS?

To re-implement all that yourself would be totally and utterly insane!

Simply use an HTML/CSS based thingy like webkit (also wrapped inside the Qt framework). Don't do it all again, you'll just make all the same mistakes...

If you want to analyse how webkit handles CSS, the source code is open.

http://www.webkit.org/

http://trac.webkit.org/browser/trunk/Source

How does browser loads DOM and CSSOM partially?

CSSOM stops parsing. Thus execution of subsequent script tags, and also delays rendering.

Script tags before style tags will execute before CSS is loaded into CSSOM from style tags afterwards.

Style tags that come after script tags will alter CSSOM. And if script accessed styles that are being altered then what it read is outdated. Order matters.

Parsing is stopped not just rendering.

JavaScript blocks parsing because it can modify the document. CSS
can’t modify the document, so it seems like there is no reason for it
to block parsing, right?

However, what if a script asks for style information that hasn’t been
parsed yet? The browser doesn’t know what the script is about to
execute—it may ask for something like the DOM node’s background-color
which depends on the style sheet, or it may expect to access the CSSOM
directly.

Because of this, CSS may block parsing depending on the order of
external style sheets and scripts in the document. If there are
external style sheets placed before scripts in the document, the
construction of DOM and CSSOM objects can interfere with each other.
When the parser gets to a script tag, DOM construction cannot proceed
until the JavaScript finishes executing, and the JavaScript cannot be
executed until the CSS is downloaded, parsed, and the CSSOM is
available

.

https://hacks.mozilla.org/2017/09/building-the-dom-faster-speculative-parsing-async-defer-and-preload/

How do browsers build a render tree before /body tag is in the DOM tree?

Your understanding is a little out, but I'll concentrate on the key point.

First the DOM does not contain individual start and end elements or tags. The pair of tags {<body>,</body>} creates a single element called body. Similarly the pair of tags {<span>,</span>} creates a single element called span.

As soon as a start tag is encountered by the parser, the element is created and added to the DOM. If the parsing stalls, the entire DOM created up to that point can be rendered - assuming that there's no render-blocking fetch going on at the time.

As for end tags, they are mostly just used to identify where the element ends so that the next element or text in the markup is not added as a child of the element that's just ended.

However, </body> is a bit of a special case. If the parser encounters tags or text after the </body> tag, the parser will "repair" the DOM by putting the elements and text as children of the body element. That's not to say that the parser ignores the </body> tag entirely - if a comment node immediately follows the </body> tag it will be added as a child of the html element, not the body element.

When will a browser parse elements which are hidden?

Browsers follow something called the Render Tree which is formed by combining the DOM and CSSOM trees. In short, the DOM is concerned about content, while CSSOM is focused on styles applied to the document. The resulting "Render Tree" contains only the visible elements required to render the page.

Elements that are not visible or hidden via CSS aka via display: none will not be included in the Render Tree, while all elements that affect the layout will be included. So, it's safe to assume that your example will not get rendered until it becomes visible or affects the layout of the document in some way.

Constructing the Render Tree

After the Render Tree is constructed, it goes through a layout and paint cycle. The layout cycle calculates the position of each element in the Render Tree, and then the paint cycle displays each element onto the screen.

For more information about the Render Tree, see Critical Rendering Path described on the Google Developers' web fundamentals resource.

How is CSS applied by the browser, and are repaints affected by it?

How does the browser take the rules in this stylesheet and apply it to the HTML?

Typically this is done in a streaming fashion. The browser reads the HTML tags as a stream, and applies what rules it can to the elements it has seen so far. (Obviously this is a simplification.)

An interesting related Q&A: Use CSS selectors to collect HTML elements from a streaming parser (e.g. SAX stream) (a diversion while I search for the article I have in mind).


Ah, here it is: Why we don't have a parent selector.

We often think of our pages as these full and complete documents full of elements and content. However, browsers are designed to handle documents like a stream. They begin to receive the document from the server and can render the document before it has completely downloaded. Each node is evaluated and rendered to the viewport as it is received.

Take a look at the body of an example document:

<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>

The browser starts at the top and sees a body element. At this point,
it thinks it's empty. It hasn't evaluated anything else. The browser
will determine what the computed styles are and apply them to the
element. What is the font, the color, the line height? After it
figures this out, it paints it to the screen.

Next, it sees a div element with an ID of content. Again, at this
point, it thinks it's empty. It hasn't evaluated anything else. The
browser figures out the styles and then the div gets painted. The
browser will determine if it needs to repaint the body—did the element
get wider or taller? (I suspect there are other considerations but
width and height changes are the most common effects child elements
have on their parents.)

This process continues on until it reaches the end of the document.

CSS gets evaluated from right to left.


To determine whether a CSS rule applies to a particular element, it
starts from the right of the rule and works it's way left.

If you have a rule like body div#content p { color: #003366; } then
for every element—as it gets rendered to the page—it'll first ask if
it's a paragraph element. If it is, it'll work its way up the DOM and
ask if it's a div with an ID of content. If it finds what it's looking
for, it'll continue its way up the DOM until it reaches the body.

By working right to left, the browser can determine whether a rule
applies to this particular element that it is trying to paint to the
viewport much faster. To determine which rule is more or less
performant, you need to figure out how many nodes need to be evaluated
to determine whether a style can be applied to an element.


So why was the stylesheet content not applied progressively (green first, then red)?

I think the answer is that external stylesheets are parsed as they are downloaded, but not applied until the entire stylesheet has been parsed. Surely, in parsing a stylesheet, the browser optimizes away unnecessary and redundant CSS rules.

I don't have any proof to back that up right now, but that explanation sounds reasonable to me and agrees with what you're seeing, both with external and inline styles.



Related Topics



Leave a reply



Submit