How do browsers read and interpret CSS?

Two part question:

  1. Do browsers have a built-in CSS interpreter like they do for JavaScript?
  2. When exactly does a browser read the CSS and when does it apply the CSS?

Specifically, I would like clarification on how or why JavaScript and CSS are different in that with JavaScript you need to specifically wait until window.onload so the interpreter can correctly getElementById. However, in CSS you can select and apply styles to classes and ids all wily nily.

(If it even matters, assume I am referring to a basic HTML page with an external stylesheet in the head)


CSS rendering is an interesting topic and all the competitors are thriving hard to speed up the view layer (HTML and CSS) rendering to deliver the best results to the end users at a blink of an eye.

Firstly, yes different browsers have their own CSS parser/Rendering engines

  • Google Chrome, Opera (from version 15) - Uses Webkit fork called Blink Rendering engine
  • Safari - uses Webkit (Now forked to Webkit2)
  • Internet Explorer - uses Trident Rendering engine. (+ Update: Edge on Windows 10 uses Chromium fork for its future versions)
  • Mozilla firefox - Uses Gecko

All these rendering engine contain both CSS interpreter and HTML DOM parser.

All these engines follow below listed models , these are the set of W3C standard

  • Visual processing Model
  • Box Model
  • CSS 2.1 Addressing Model

Note: All these models are interlinked and interdependent. They are not separate models defining standards to render the CSS. These models shed light on how CSS is processed based on precedence like inline styling, Specificity etc.


Explanation:


Stage 1:


All the browsers download the HTML and CSS script from the server and start off by parsing HTML tags to DOM nodes in a tree called content tree.

While the HTML doc being parsed browser rendering engines construct another tree called the Render tree. This tree is of visual elements in the order in which they will be displayed.

Firefox call it as frames where as Webkit guys call them as Renderer or Renderer object.

See the below image: (Source: HTML5 Rocks)

enter image description here


Stage 2:


After the above process both these tree goes through Layout process meaning the browser tells the viewport where each node has to be placed on the screen.

This is defined as positioning scheme by W3C(Follow this link for detailed info) which instructs the browser on how and where elements are to be placed. Below are the 3 types.

  • Normal Flow
  • Floats
  • Absolute position

Stage 3:


Now the final stage called Painting. This is a gradual process where the rendering engine traverse through each render tree nodes and paint them visually using UI backend layer. At this point all the visual Fx are applied like Font size, Background color, Table painting etc.

Note: This stage can be clearly observed if you try to open any webpage on slow connection. Most modern browsers for better user experience try to display elements as soon as possible. This gives the user an impression that the page is loading and have to wait to complete.


Block diagram of the workflow for better understanding

Source HTML5 Rocks

  • Webkit:

enter image description here

  • Mozilla's Gecko: enter image description here

References:(Please read the below links. They are best resources available on the Web pertaining to this topic)

  • http://www.html5rocks.com/en/tutorials/internals/howbrowserswork/ (Best explaination)
  • http://www.slideshare.net/ariyahidayat/understanding-webkit-rendering
  • https://html.spec.whatwg.org/multipage/syntax.html#parsing
  • http://dbaron.org/talks/2008-11-12-faster-html-and-css/slide-3.xhtml
  • https://css-tricks.com/almanac/properties/t/text-rendering/
  • https://www.webkit.org/blog/114/webcore-rendering-i-the-basics/
  • http://www.w3.org/TR/CSS21/intro.html#addressing

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.


Yes, browsers have a CSS interpreter built in. The reason you don't "wait until window.onload" is because while Javascript is a Turing-complete imperative programming language, CSS is simply a set of styling rules that the browser applies to matching elements it encounters.


Browsers read CSS lines from right to left. That's what both Google as Mozilla say. Google says 'The engine evaluates each rule from right to left' on http://code.google.com/speed/page-speed/docs/rendering.html. Mozilla says 'The style system matches rules by starting with the key selector, then moving to the left' on https://developer.mozilla.org/en/Writing_Efficient_CSS

Take for example this CSS line: '.item h4'. The browser first searches for the all the 'h4' tags on the page and then looks if the h4 tag has a parent with the class name 'item'. If it finds one, it applies the CSS rule.


I recently bumped into this article on google page speed:

As the browser parses HTML, it constructs an internal document tree representing all the elements to be displayed. It then matches elements to styles specified in various stylesheets, according to the standard CSS cascade, inheritance, and ordering rules. In Mozilla's implementation (and probably others as well), for each element, the CSS engine searches through style rules to find a match. The engine evaluates each rule from right to left, starting from the rightmost selector (called the "key") and moving through each selector until it finds a match or discards the rule. (The "selector" is the document element to which the rule should apply.)

http://code.google.com/speed/page-speed/docs/rendering.html