refer: howbrowserswork
The job of the HTML parser is to parse the HTML markup into a parse tree.
The output tree - the parse tree is a tree of DOM element and attribute nodes.The DOM has an almost one to one relation to the markup. Example, this markup:
<html> <body> <p> Hello World </p> <div> <img src="example.png"/></div> </body> </html>
Each CSS file is parsed into a StyleSheet object, each object contains CSS rules. The CSS rule objects contain selector and declaration objects and other object corresponding to CSS grammar.
While the DOM tree is being constructed, the browser constructs another tree, the render tree. This tree is of visual elements in the order in which they will be displayed
Firefox calls the elements in the render tree “frames”. Webkit uses the term renderer or render object. A renderer knows how to layout and paint itself and it's children. Webkits RenderObject class, the base class of the renderers has the following definition:
class RenderObject{ virtual void layout(); virtual void paint(PaintInfo); virtual void rect repaintRect(); Node* node; //the DOM node RenderStyle* style; // the computed style RenderLayer* containgLayer; //the containing z-index layer }
Each renderer represents a rectangular area usually corresponding to the node's CSS box, as described by the CSS2 spec. It contains geometric information like width, height and position.
The box type is affected by the “display” style attribute that is relevant for the node (see the style computation section). Here is Webkit code for deciding what type of renderer should be created for a DOM node, according to the display attribute.
RenderObject* RenderObject::createObject(Node* node, RenderStyle* style) { Document* doc = node->document(); RenderArena* arena = doc->renderArena(); ... RenderObject* o = 0; switch (style->display()) { case NONE: break; case INLINE: o = new (arena) RenderInline(node); break; case BLOCK: o = new (arena) RenderBlock(node); break; case INLINE_BLOCK: o = new (arena) RenderBlock(node); break; case LIST_ITEM: o = new (arena) RenderListItem(node); break; ... } return o; }
he renderers correspond to the DOM elements, but the relation is not one to one.
Building the render tree requires calculating the visual properties of each render object. This is done by calculating the style properties of each element.
Firefox has two extra trees for easier style computation - the rule tree and style context tree. Webkit also has style objects but they are not stored in a tree like the style context tree, only the DOM node points to its relevant style.
Figure: Firefox style context tree
The style contexts contain end values. The values are computed by applying all the matching rules in the correct order and performing manipulations that transform them from logical to concrete values.
Lets see an example: Suppose we have this HTML
<html> <body> <div class="err" id="div1"> <p> this is a <span class="big"> big error </span> this is also a <span class="big"> very big error</span> error </p> </div> <div class="err" id="div2">another error</div> </body> </html>
And the following rules:
To simplify things let's say we need to fill out only two structs - the color struct and the margin struct. The color struct contains only one member - the color The margin struct contains the four sides.
The resulting rule tree will look like this (the nodes are marked with the node name : the # of rule they point at):
The context tree will look like this (node name : rule node they point to):
The stacking order of a block renderer is:
Each box has a content area (e.g., text, an image, etc.) and optional surrounding padding, border, and margin areas.
Each node generates 0..n such boxes.
All elements have a “display” property that determines their type of box that will be generated.
Examples:
block - generates a block box. inline - generates one or more inline boxes. none - no box is generated.
The default is inline but the browser style sheet set other defaults. For example - the default display for “div” element is block
There are three schemes:
The positioning scheme is set by the “position” property and the “float” attribute:
Block box: forms a block - have their own rectangle on the browser window.
Figure:Block box
Inline box: does not have its own block, but is inside a containing block.
Figure:Inline boxes
Blocks are formatted vertically one after the other. Inlines are formatted horizontally.
Figure:Block and Inline formatting
Inline boxes are put inside lines or “line boxes”. The lines are at least as tall as the tallest box but can be taller, when the boxes are aligned “baseline” - meaning the bottom part of an element is aligned at a point of another box other then the bottom. In case the container width is not enough, the inlines will be put in several lines. This is usually what happens in a paragraph.
Figure:Lines
Relative positioning - positioned like usual and then moved by the required delta.
Figure:Relative positioning
A float box is shifted to the left or right of a line. The interesting feature is that the other boxes flow around it The HTML:
Figure:Float
The layout is defined exactly regardless of the normal flow. The element does not participate in the normal flow. The dimensions are relative to the container. In fixed - the container is the view port.
Figure:Fixed positioning
Note - the fixed box will not move even when the document is scrolled!
It is specified by the z-index CSS property. It represents the 3rd dimension of the box, its position along the “z axis”.
The boxes are divided to stacks (called stacking contexts). In each stack the back elements will be painted first and the forward elements on top, closer to the user. In case of overlap the will hide the former element.
The stacks are ordered according to the z-index property. Boxes with “z-index” property form a local stack. The viewport has the outer stack.
Example:
<STYLE type="text/css"> div { position: absolute; left: 2in; top: 2in; } </STYLE> <P> <DIV style="z-index: 3;background-color:red; width: 1in; height: 1in; "> </DIV> <DIV style="z-index: 1;background-color:green;width: 2in; height: 2in;"> </DIV> </p>
html, address, blockquote, body, dd, div, dl, dt, fieldset, form, frame, frameset, h1, h2, h3, h4, h5, h6, noframes, ol, p, ul, center, dir, hr, menu, pre { display: block; unicode-bidi: embed } li { display: list-item } head { display: none } table { display: table } tr { display: table-row } thead { display: table-header-group } tbody { display: table-row-group } tfoot { display: table-footer-group } col { display: table-column } colgroup { display: table-column-group } td, th { display: table-cell } caption { display: table-caption } th { font-weight: bolder; text-align: center } caption { text-align: center } body { margin: 8px } h1 { font-size: 2em; margin: .67em 0 } h2 { font-size: 1.5em; margin: .75em 0 } h3 { font-size: 1.17em; margin: .83em 0 } h4, p, blockquote, ul, fieldset, form, ol, dl, dir, menu { margin: 1.12em 0 } h5 { font-size: .83em; margin: 1.5em 0 } h6 { font-size: .75em; margin: 1.67em 0 } h1, h2, h3, h4, h5, h6, b, strong { font-weight: bolder } blockquote { margin-left: 40px; margin-right: 40px } i, cite, em, var, address { font-style: italic } pre, tt, code, kbd, samp { font-family: monospace } pre { white-space: pre } button, textarea, input, select { display: inline-block } big { font-size: 1.17em } small, sub, sup { font-size: .83em } sub { vertical-align: sub } sup { vertical-align: super } table { border-spacing: 2px; } thead, tbody, tfoot { vertical-align: middle } td, th, tr { vertical-align: inherit } s, strike, del { text-decoration: line-through } hr { border: 1px inset } ol, ul, dir, menu, dd { margin-left: 40px } ol { list-style-type: decimal } ol ul, ul ol, ul ul, ol ol { margin-top: 0; margin-bottom: 0 } u, ins { text-decoration: underline } br:before { content: "\A"; white-space: pre-line } center { text-align: center } :link, :visited { text-decoration: underline } :focus { outline: thin dotted invert } /* Begin bidirectionality settings (do not change) */ BDO[DIR="ltr"] { direction: ltr; unicode-bidi: bidi-override } BDO[DIR="rtl"] { direction: rtl; unicode-bidi: bidi-override } *[DIR="ltr"] { direction: ltr; unicode-bidi: embed } *[DIR="rtl"] { direction: rtl; unicode-bidi: embed } @media print { h1 { page-break-before: always } h1, h2, h3, h4, h5, h6 { page-break-after: avoid } ul, ol, dl { page-break-before: avoid } }