In the previous article, we looked at an overview of the technologies that websites are built from. In this article we walk through the process by which those technologies are rendered — when a browser has received the code files and other assets that make up a web page (as covered in How the web works), how are they put together to create the finished experience that the user interacts with?Prerequisites: Basic familiarity with your computer operating system, web browsers, and web technologies. Learning outcomes:
To summarize the overview of web technologies we looked at in the last article, HTTP responses (to requests for a web page) will generally contain some of the following file types:
When the user navigates to a new web page (by clicking a link, or entering a web address in the browser address bar), several HTTP requests are sent, and several files are sent back in HTTP responses. The files received in these responses are processed by the browser and put together into a web page that the user can interact with. This process of assembling the pieces into a web page is called rendering.
The following sections provide a high-level explanation of how a browser renders a web page. Keep in mind that this is a simplified description, and that different browsers will handle the process in different ways. However, this will still give you an idea of how things work.
To start with, the HTML file that contains the web page content and defines its structure is received by the browser, and parsed. The browser converts it into a tree-like structure called a DOM tree (Document Object Model). The DOM represents the HTML document structure in the computer's memory. Take this basic HTML snippet as an example:
<p>
Let's use:
<span>HTML</span>
<span>CSS</span>
<span>JavaScript</span>
</p>Each element, attribute, and piece of text in the HTML becomes a DOM node in the tree structure. The nodes are defined by their relationship to other DOM nodes. Some elements are parents of child nodes, and child nodes have siblings. The browser will parse this HTML and create the following DOM tree from it:
P
├─ "Let's use:"
├─ SPAN
| └─ "HTML"
├─ SPAN
| └─ "CSS"
└─ SPAN
└─ "JavaScript"In this DOM tree, the node corresponding to our <p> element is a parent. Its children include a text node and the three nodes corresponding to our <span> elements. The SPAN nodes are also parents, with text nodes as their children. When the browser renders this DOM tree, it will look like so:
Certain HTML elements, when parsed, will trigger more HTTP requests:
<link> elements referencing external CSS stylesheets.<script> elements referencing external JavaScript files.<img>, <video>, and <audio>, which reference media files you want to embed in the web page.Next, the CSS is handled.
The following diagram offers a visualization of the process we've talked about so far:
Going back to our example, let's say the following CSS is found in the HTML file:
span {
border: 1px solid black;
background-color: lime;
}The only rule available in the CSS has a span selector, so the browser is able to sort the CSS very quickly! It applies that rule to each one of the three SPAN nodes in the DOM tree, giving them a black border and a lime green background, then paints the final visual representation to the screen.
The updated output is as follows:
After the CSS has been handled, any JavaScript found on the page (either included in the HTML file, or fetched from external script files) is parsed, interpreted, compiled, and executed. This happens at some point before the final page rendering is completed — after all, some JavaScript may affect the rendering, for example by adding nodes to the DOM or modifying existing ones.
Returning to our example, let's say the following JavaScript is found in the HTML file:
const spans = document.querySelectorAll("span");
spans.forEach((span) => {
const reversedText = span.textContent.split("").reverse().join("");
span.textContent = reversedText;
});You don't need to understand exactly how this JavaScript works, but at a high level, it finds every SPAN node in the DOM and reverses the order of the characters in their child text nodes.
The final output is as follows:
Several other things happen during page rendering, but we won't discuss them all here. One notable additional occurrence worth mentioning is that an accessibility tree is built, based on the DOM, for assistive technologies (for example screen readers) to hook into, which enables people who are not able to see the rendered content to interact with it.
You will learn more about this later on, in our Accessibility module.
Front-end web development can sometimes be frustrating, and some people consider the browser to be a hostile programming environment. This is because, unlike other programming environments, it is much harder to make guarantees about the environment your code will run on. You cannot know ahead of time all the different combinations of operating system, browser, language, location, network connection, CPU, GPU, memory, battery life, etc., that your users will have, therefore you cannot guarantee a perfect user experience for all of them.
Modern browsers tend to implement web standards pretty consistently, but there is still a lot of uncertainty to navigate. As a web developer, you will need to embrace that uncertainty, programming defensively and being conservative with the features you use. This relies on adhering to the best practices outlined in the previous article.
On the upside, the web is also an awesome programming environment, for many reasons.
If something isn't working as expected in a browser, it could be a browser bug. This article explains how to figure out if it is, and how to file a bug report if so.