In previous article, the toy browser parsed and tokenized a HTML file. After that, it built a DOM Tree mounted with all the computed CSS rules. A question is remained: How to render a
div having a CSS
flex: 1 ?
In this article, the last one of toy browser series, I will resolve this problem, and render an image from DOM Tree.
There are several kinds of CSS layouts:
- Normal flow
- Grid layout
To make the toy browser simple, I will focus on Flexbox, which is very useful in daily work. There is an awesome article that explains how Flexbox works: A Complete Guide to Flexbox. If you are not familiar with Flexbox, please read it. The code of the function
layout will help you to understand this part, too.
The general idea of this part is to translate the rules of Flexbox into 10 properties:
- mainSize, mainStart, mainEnd, mainSign, mainBase
- crossSize, crossStart, crossEnd, crossSign, crossBase
They are well explained by MDN. Here,
mainSign is a boolean. If the writing mode is from left to right on the main axis, it will be true.
mainBase is the starting position of flex item in the flex container of the main axis. It is the same for the cross axis.
Having the general idea, let’s dive deeper to understand how the toy browser deals with Flexbox. In general, it takes 3 steps to calculate Flexbox.
- calculate flex container’s size
- calculate flex items by the main axis
- calculate flex items by the cross axis
When the HTML Parser is in endTag step during the tokenization, it will call the function
layout to translate CSS layout, which is Flexbox in our toy browser. A node of DOM Tree is sent to the function.
When the function
layout meets a node with
display = flex , it knows that the current node and its children follow the layout of Flexbox. It will start translating.
Before the calculating, it determines the main axis and cross axis by
Calculating of flex container’s size
The flex container is saved in an array, call
flexLines . Each item in it is a “line” of flex items. Flexbox is responsive, it will change line automatically when there are too many items in a line. The notion “line” help us deal with changing line.
There are only two cases that Flexbox will not change line:
flexWrap=”nowrap”: all the flex items are forced to be put inline. If the flex item is too big, it need to be scaled.
- flex item has the attribute
flex: the flex item must be placed inline. The space it takes is defined by the proportion.
Calculating of main axis
Once the flex container’s size is calculated, the function
layout starts to calculate flex items by main axis. It reads two pieces of information:
flex in flex item or
justify-content in the flex container. As the result, for
row mode, the
width of each flex item will be calculated.
If the flex items have the attribute
flex , the function
layout needs to know the total of the
flex in the flex container, and split the main axis space by the proportion of space that each flex item has. For example:
<div style="display: flex;">
<div style="flex: 1;">1</div>
<div style="flex: 2;">2</div>
div takes one third of the flex container’s main axis space, while the second takes two third.
If the flex container has the attribute
justify-content , the function
layout calculates the start point of each flex item and the space between 2 flex items on main axis. These 2 variables are depended on the value of
justify-content , such as
Calculating of cross axis
Once the calculation on the main axis is finished, the function
layout starts to calculate flex items by cross axis. This time, the function checks
align-self of flex item and
align-content of flex content. As the result, for
row mode, the
bottom of each flex item will be calculated.
align-content helps define the start point of each flex item and the space between 2 flex items on cross axis. It has the value, like
With the start point and the space, the function continues calculating using
align-self . It has the value, like
stretch . Combine
align-self , the cross axis is finally calculated.
An example is as followed. The height, width, top, bottom of a flex container and one of its flex item are calculated.
With the information of
bottom , the toy browser can render the image easily. I used a package images.
In the demo, the toy browser initialise the viewport with 800px width and 600px height. Its background color is black.
The flex container has the white background color. It has 3 children.
div: its height and width is initialised by hand
div: it has the attribute
div: it has the attribute
As the result, the width of the blue
div is twice as the green one.
In this article, I presented how a toy browser gets the
bottom from Flexbox, and renders an image with this information. For now, the toy browser works, but it’s very naive. It can’t deal with many basic layout properties, such as
padding , etc.
In this toy browser series, I presented the workflow of a browser:
- sent HTTP request to a server , and receive, parse the response
- parse, tokenize the response body, and create a DOM Tree mounted with CSS rules
- get the layout from the Flexbox, and render an image from the DOM Tree
Hope this series help you understand how the browser works.
Thanks for reading, and see you next time.