[Toy Browser] Layout and Rendering

Introduction: [Toy Browser] Introduction
Previous article: [Toy Browser] HTML parsing and CSS computing
Keywords: CSS, DOM Tree, image rendering
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.
CSS Layout
There are several kinds of CSS layouts:
- Normal flow
- Flexbox
- 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 flewDirection
.
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 height
and 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>
The first 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 flex-start
, flex-end
, center
, space-between
, space-around
.
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 top
and bottom
of each flex item will be calculated.
Similar to justify-content
, 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 flex-start
, flex-end
, center
, space-between
, space-around
, stretch
.
With the start point and the space, the function continues calculating using align-self
. It has the value, like flex-start
, flex-end
, center
, stretch
. Combine align-content
and 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.

Rendering
With the information of height
, width
, top
, 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.
- red
div
: its height and width is initialised by hand - green
div
: it has the attributeflex: 1
- blue
div
: it has the attributeflex: 2
As the result, the width of the blue div
is twice as the green one.

Here is the HTML file, and the code of rendering.
Conclusion
In this article, I presented how a toy browser gets the height
, width
, top
, 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 margin
, 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.