A thought triggered by an interview question:

What happens from user input to browser url input to final page rendering? A very routine topic, examination is the basic network principle, and the browser load CSS, JS process.

The answers are as follows:

  1. The user enters the URL address

  2. The browser parses the URL to resolve the host name

  3. The browser converts the host name to the server IP address. (The browser first looks up the local DNS cache list and then sends a query request to the browser’s default DNS server.)

  4. The browser interprets the port number from the URL

  5. The browser establishes a TCP connection to the target Web server (three-way handshake)

  6. The browser sends an HTTP request packet to the server

  7. The server returns an HTTP response packet to the browser

  8. Close the connection browser to parse the document

  9. If there are resources in the document, repeat actions 6, 7, 8 until all resources are loaded

The answers above briefly outline the principles behind the basic response process of a web page. But that’s only part of it, the part where the browser gets the data, and how the browser renders the page after it gets the data, it doesn’t pay much attention. So take the time to study how your browser renders pages. Through research, understand some basic principles of common sense:

  1. Why put JS in the footer

  2. Introduce weights in several ways for styles

  3. The writing sequence of CSS attributes is recommended

  4. What kind of DOM manipulation is performance-costly

Browser rendering main flow

Different browsers have different kernels, so the rendering process is different.

Its main process

Mozilla’s Gecko rendering engine main flow

As you can see from the above two figures, although the rendering process is called differently in the major browsers, the main process is the same. Gecko refers to a tree of visual formatting elements as a “frame tree.” Each element is a framework. WebKit uses the term “render tree”, which consists of “render objects”. WebKit uses the term “layout” for the placement of elements, which Gecko calls “rearrangement.” The term WebKit uses for the process of connecting DOM nodes and visual information to create a rendering tree is “attach.”

So the basic process can be analyzed:

  1. The HTML parses the DOM Tree

  2. The CSS parses the Style Rules

  3. Correlate the two to generate a Render Tree

  4. Layout calculates the information for each node according to the Render Tree

  5. Painting Paints the entire page based on the calculated information

HTML parsing

The FUNCTION of the HTML Parser is to parse HTML tags into a DOM Tree. You can see how React parses the DOM, but there are many other rules and operations, such as fault tolerance, recognition of

and

, etc. You can refer to How Browser Work for an example: a piece of HTML

<html>
<head>
    <title>Web page parsing</title>
</head>
<body>
    <div>
        <h1>Web page parsing</h1>
        <p>This is an example Web page.</p>
    </div>
</body>
</html>Copy the code

The parsed DOM Tree looks something like this

The text of THE HTML document, extract the key information, nested hierarchical tree structure, easy to calculate expansion. That’s what the HTML Parser is for.

CSS analytical

CSS Parser parses CSS into Style Rules, also known as CSSOM (CSS Object Model). StyleRules are also Tree structures, similar to DOM trees, arranged from CSS files:

Similar to HTML Parser, CSS Parser combines styles from many CSS files to parse out Style Rules with a tree structure.

Script processing

The browser parses the document, and when it encounters a

Render Tree

Render Tree construction is actually a process of DOM Tree and CSSOM Attach. Renderers correspond to DOM elements, but not one-to-one. The Render Tree is essentially a Tree that calculates the style of the HTML (including what to display and what not to display).

In WebKit, the process of parsing styles and creating renderers is called “attaching.” Each DOM node has an “Attach” method. Attaching is done synchronously, and inserting a node into the DOM tree requires calling a new node “Attach” method.

Style calculation

Style calculation is a very complex problem. A single element in the DOM can correspond to multiple elements in a stylesheet. Style sheets include all styles: browser default style sheets, custom style sheets, inline style elements, and HTML visual attributes such as width=100. The latter will be transformed to match the CSS style.

WebKit nodes reference style objects (RenderStyle). These objects can be shared by different nodes in some cases. These nodes are peers and:

  1. These elements must be in the same mouse state (for example, one is not allowed to be in the “:hover” state while the other is not)

  2. There is no ID for any element

  3. Tag names should match

  4. Class attributes should match

  5. The set of mapping attributes must be identical

  6. Link states must match

  7. The focus states must match

  8. No element should be affected by the attribute selector, and by “affected” I mean any selector matches that use the attribute selector anywhere in the selector

  9. The element cannot have any inline style attributes

  10. You cannot use any sibling selectors. WebCore only raises a global switch when it encounters any sibling selector and deactivates style sharing for the entire document, if one exists. This includes + selectors as well as :first-child and: last-Child selectors.

To simplify style calculations, Firefox uses two other trees: the rule tree and the style context tree. WebKit also has style objects, but they are not stored in a tree structure like a style context tree, just the associated styles of such objects that are pointed to by DOM nodes.

The style context contains the end values. To calculate these values, apply all the matching rules in the correct order and convert them from logical values to concrete values. For example, if the logical value is a percentage of screen size, you need to convert it to absolute units. The idea of a rule tree is really clever, as it allows nodes to share these values to avoid double-counting and to save space. All matching rules are stored in the tree. The underlying node in the path has a higher priority. The rule tree contains the path of all known rule matches. The storage of rules is delayed. The rule tree does not start the calculation for all nodes, but adds a path to the rule tree only when a node style requires the calculation.

For example, we have this HTML code:

<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>Copy the code

The CSS rules are as follows:

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}Copy the code

The rule tree formed by the CSS is as follows (nodes are marked as “node name: Rule number pointing to”).

Suppose we encounter a second

tag while parsing HTML, and we need to create a style context for this node and populate its style structure. After rule matching, we find that the

matches rules 1, 2, and 6. This means that there is already one path in the rule tree available to our element, and we just need to add another node to match rule 6 (the F node in the rule tree). We will create the style context and place it in the context tree. The new style context points to the F node in the rule tree.

Now we need to fill in the style structure. The first thing to fill in is the margin structure. Since the last rule node (F) is not added to the margin structure, we need to go up the rule tree until we find the cache structure computed in the previous node insertion, and then use that structure. We will find this structure on the topmost node (B node) of the specified margin rule.

We already have the color structure defined, so we can’t use the cached structure. Since color has one property, we do not need to go up the rule tree to populate the other properties. We compute side values (converting strings to RGB, etc.) and cache the computed structure on this node.

The second <span> element is simpler to handle. We will match the rule and find that it points to rule G just like the previous span. Now that we have found a sibling pointing to the same node, we can share the entire style context, just pointing to the previous span context.

For structures that contain rules inherited from their parent, caching is done in the context tree (the color property is actually inherited, but Firefox treats it as a reset property and caches it in the rule tree) so the resulting context tree looks like this:

Apply the rules in the correct cascading order

The style object has attributes (all CSS attributes but more generic) that correspond to each visual attribute. If an attribute is not defined by any matching rules, then some attributes can be inherited by the parent element style object. Other attributes have default values. If there is more than one definition, there is a problem that needs to be solved by cascading order.

Some examples:

* {} /* a=0 b=0 c=0 d=0 -> nine =0 c=0 d=1 -> nine =0 c=0 d=1 -> nine =0 {} / * = 0 b = 0 c = 0 d = 2 - > specificity = 0,0,0,2 * / ul li {} / * = 0 b = 0 c = 0 d = 2 - > specificity = 0,0,0,2 * / ul ol li + {} / * A =0 b=0 C =0 D =3 -> nine =0,0,0,3 */ h1 + *[rel=up]{} /* a=0 b=0 c=1 d=1 -> nine =0,0,1,1 */ ul OL Li.red {} /* a=0 b=0 c=1 d=3 -> auus =0,0,1,3 */ li.red A = 0 # x34y {} / * b = c = 0 1 d = 0 - > specificity = 0,1,0,0 * / style = "" / * a = b = 0 c = 0 1 d = 0 - > specificity = 1,0,0,0 * /Copy the code

Using the above method, the priority of different selectors can be determined quickly.

Layout of the Layout

After creating the render tree, the next step is a Layout, or reflow (relayout). This process takes information from the render objects in the tree, calculates the position and size of each render object, and places it in the correct position in the browser window. Sometimes we modify the DOM after the layout of the document is complete. In this case, we may need to rearrange, also called backflow, which is essentially a layout process. Each rendered object has a layout or backflow method that implements its layout or backflow.

The layout of the rendering tree can be divided into global and local, global means to rearrange the entire rendering tree, such as when we change the size or direction of the window or modify the size of the root element or font size; A local layout can be a rearrangement of a part of the render tree or a render object.

Most Web applications operate on the DOM quite frequently, which means that the DOM needs to be laid out and reflowed all the time, and small changes can trigger reflowback of the entire render tree, which is obviously bad. To avoid this, browsers use dirty bit systems. Backflow is required when only one render object has changed or a render object and its children have dirty bits.

There are two types of dirty bit values that represent the desired layout:

  • “Dirty” – Changes itself and requires backflow

  • “Children are dirty” – Children have changed and need to backflow

Layout is a recursive process from top to bottom and from outside to inside, rendering objects at the root, corresponding to the HTML document root, and then rendering objects at the next level, corresponding to the elements, and so on, calculating the geometric information (position and size) for each rendered object in turn.

The layout flow of each render object is as follows:

  • 1. Calculate the width of this render object;

  • 2. Iterate through all the children of the render object, in order:

    • 2.1 Set the coordinates of child render objects

    • 2.2 Determine whether the layout or backflow method of the child rendering object needs to be triggered to calculate the height of the child rendering object.

  • 3. Set the height of the render object: Set the height of the child render object according to the cumulative height, margin and padding height;

  • 4. Set the dirty bit value of this render object to false.

Painting

In the paint phase, the rendering tree is traversed and the renderer’s “paint” method is called to display the renderer’s contents on the screen. Drawing is done using user interface infrastructure components.

The CSS2 specification defines the order in which a process is drawn. The order in which the elements are drawn is the order in which they enter the stack style context. These stacks are drawn from back to front, so this order affects the drawing. The stack order of the block renderer is as follows:

  1. The background color

  2. The background image

  3. A border

  4. Their offspring

  5. outline

There are two more concepts, one is Reflow and the other is Repaint. The two are not the same thing. Repaint — Part of the screen needs to be repainted, such as a CSS background color that changes. But the geometry of the elements does not change. Reflow component geometry has changed and we need to revalidate and evaluate the Render Tree. Some or all of Render Tree has changed. That’s a Reflow, or Layout. (HTML uses a flow based layout, so if the geometry of an element changes and needs to be rearranged, reflow will recursively start with the root frame < HTML >, Calculate the geometry and position of all nodes in turn. During reflow, some frames may be added, such as a text string that must be wrapped.

Reflow costs much more than Repaint. Every node in a DOM Tree has a reflow method, and a node’s reflow is likely to result in reflows for its children, or even its parents, and siblings. On some high-powered computers this may not be a problem, but if reflow occurs on mobile phones, the process can be very painful and power-hungry. Therefore, the following actions are likely to be relatively expensive.

  • When you add, delete, or modify DOM nodes, Reflow or Repaint will result

  • When you move the DOM, or when you animate it.

  • When you modify the CSS style.

  • When you Resize the window (mobile doesn’t have this problem), or when you scroll.

  • When you change the default font of a web page.

  • Note: Display: None will trigger reflow, while visibility: Hidden will only trigger repaint because no position changes are found.

Basically, there are several reasons for reflow:

  • Initial. When the page is initialized.

  • Incremental. Some Javascript works with a DOM Tree.

  • The Resize. The dimensions of some of its components have changed.

  • StyleChange. If the properties of the CSS change.

  • The Dirty. Several Incremental reflows occur on a subtree of the same frame.

Look at a few examples:

$('body').css('color', 'red'); // repaint $('body').css('margin', '2px'); // reflow, repaint var bstyle = document.body.style; // cache bstyle.padding = "20px"; // reflow, repaint bstyle.border = "10px solid red"; // Reflow and repaint bstyle.color = "blue"; // repaint bstyle.backgroundColor = "#fad"; // repaint bstyle.fontSize = "2em"; // reflow, repaint // new DOM element - reflow, repaint document.body.appendChild(document.createTextNode('dude! '));Copy the code

Of course, our browser is smart, it doesn’t reflow or repaint every time you change styles like above. Typically, browsers accumulate a batch of these operations and do a reflow, also known as asynchronous or incremental asynchronous reflow. But there are cases where browsers don’t do this, such as resize Windows, changing the default font on a page, and so on. For these operations, the browser reflow immediately.

Sometimes, however, our script prevents the browser from doing this, for example, if we request the following DOM values:

offsetTop, offsetLeft, offsetWidth, OffsetHeight scrollTop/Left/Width/Height clientTop/Left/Width/Height of the IE getComputedStyle (), or currentStyleCopy the code

Because, if our program needs these values, the browser will need to return the latest values, and this will flush out some style changes, resulting in frequent reflow/ Repaint.

Chrome debugger looks at page rendering order

Page rendering details can be viewed through Timeline in chrome developer Tools

  1. Initiate a request;

  2. Parsing HTML;

  3. Parsing style;

  4. Execute JavaScript;

  5. Layout;

  6. draw

Page rendering optimization

Browsers have made a lot of improvements to the key render paths described above, making as few changes as possible for each change, and optimizing the way they judge redrawing or layout, among other things. Changing the font color of the root element and other visual information will trigger the redrawing of the entire document, while changing the font color of an element will only trigger the redrawing of a specific element. Changing the location of an element triggers both the layout and redrawing of that element (and possibly its siblings or children). Some major changes, such as changing the font size of the document root element, can trigger a relayout and redrawing of the entire document, so the following optimizations and practices are recommended as described above:

  1. HTML document structure as few as possible, preferably no deeper than six layers;

  2. Script as far as possible after put, put before can;

  3. A small number of front-screen styles are placed inline in the label;

  4. The style structure hierarchy should be as simple as possible;

  5. Minimize DOM operations in scripts and cache DOM access style information to avoid excessive backflow.

  6. Reduce the use of JavaScript code to modify element styles and use class names to manipulate styles or animations.

  7. Animation should be used on absolutely positioned or fixed positioned elements;

  8. Hide out of the screen, or when the page is scrolling, try to stop the animation;

  9. Cache DOM lookup as much as possible, and make the finder as simple as possible;

  10. For websites with multiple domain names, you can enable domain name pre-resolution

conclusion

Browser rendering is a tedious process, with an algorithm for each step. Understanding the principles of the rendering process can lead to performance optimization, as well as understanding some of the basic requirements and principles of the specification. Finally, many sentences in the middle of the article are directly copied from the original, their own language overview is not as wonderful as the original.

Refer to the link

  1. How Browser Work

  2. How browsers work: Behind the scenes of the new Web browser

  3. How browsers render

  4. Brief analysis of the front-end page rendering mechanism

  5. Browser rendering, rendering process and performance optimization

  6. Optimized CSS rearrangement redraw with browser performance