User Tools

Site Tools


webdesign:howbrowserwork

How Browser Work and HTML Language

Rendering engines

The main flow

Main flow examples

Figure: Webkit main flow

Figure: Mozilla's Gecko rendering engine main flow

Parsing and DOM tree construction

HTML Parser and DOM

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>

Would be translated to the following DOM tree:

CSS parsing

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.

Render tree construction

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

The render tree relation to the DOM tree

he renderers correspond to the DOM elements, but the relation is not one to one.

  • Non visual DOM elements will not be inserted in the render tree. An example is the “head” element.
  • Also elements whose display attribute was assigned to “none” will not appear in the tree (elements with “hidden” visibility attribute will appear in the tree).
  • There are DOM elements which correspond to several visual objects. These are usually elements with complex structure that cannot be described by a single rectangle. For example, the “select” element has 3 renderers - one for the display area, one for the drop down list box and one for the button
  • Some render objects correspond to a DOM node but not in the same place in the tree. Floats and absolutely positioned elements are out of flow, placed in a different place in the tree, and mapped to the real frame

Style Computation

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

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.

Computing the style contexts using the rule tree

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:

  1. div {margin:5px;color:black}
  2. .err {color:red}
  3. .big {margin-top:3px}
  4. div span {margin-bottom:4px}
  5. #div1 {color:blue}
  6. #div2 {color:green}

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


Figure: The rule tree

The context tree will look like this (node name : rule node they point to):


Figure: The context tree

Painting

The painting order

The stacking order of a block renderer is:

  1. background color
  2. background image
  3. border
  4. children
  5. outline

CSS2 visual model

CSS Box model

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

Positioning scheme

There are three schemes:

  • Normal - the object is positioned according to its place in the document - this means its place in the render tree is like its place in the dom tree and layed out according to its box type and dimensions
  • Float - the object is first layed out like normal flow, then moved as far left or right as possible
  • Absolute - the object is put in the render tree differently than its place in the DOM tree

The positioning scheme is set by the “position” property and the “float” attribute:

  • static and relative cause a normal flow
  • absolute and fixed cause an absolute positioning

Box types

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

Position

Relative

Relative positioning - positioned like usual and then moved by the required delta.

Figure:Relative positioning

Floats

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

Absolute and fixed

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!

Layered representation

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>

The result will be this:

Default style sheet for HTML 4

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 }
}
webdesign/howbrowserwork.txt · Last modified: 2017/01/12 09:12 (external edit)