PLAINFINCH learn by building

How HTML works

You will understand how a browser reads HTML and turns it into the page you see.

What is HTML actually describing?

HTML stands for HyperText Markup Language. You write plain text and wrap parts of it in tags that tell the browser what each part is: a heading, a paragraph, a link, a list, a form field. The browser reads those labels and decides how to display them, how keyboard users move through them, and what a screen reader announces.

The key word is meaning. When you write <h2>Opening hours</h2> you are saying "this is a second-level heading". The bold, larger text is a side effect of the browser's default stylesheet. Screen reader users can jump from heading to heading, search engines treat the text as a topic label, and browser reader modes use it to build an outline. None of that happens if you fake a heading with a styled <div>.

HTML has no variables, loops or conditions. It describes a document. Behaviour comes from JavaScript and appearance comes from CSS, and both hook onto the structure HTML provides.

<h2>Opening hours</h2>
<p>We bake from 6am. The shop opens at 7.</p>
<a href="/menu.html">See today's menu</a>

What happens between typing a URL and seeing the page?

Your browser asks a server for the file at that address. The server replies with a status code such as 200 OK or 404 Not Found, a set of headers, and the HTML text. One header, Content-Type: text/html; charset=utf-8, tells the browser to treat the bytes as HTML and how to decode them into characters.

The browser then parses the text from top to bottom. Each time it meets a <link rel="stylesheet">, <img> or <script>, it starts fetching that file too. A plain <script> without defer or async pauses parsing until the script has downloaded and run, which is why scripts usually go at the end of the body or carry defer.

Once the browser has the document tree and the CSS, it works out the size and position of every box (layout), fills in pixels (paint) and shows the result. Images that arrive later trigger another layout, which is why a page can jump around unless images have width and height attributes.

You can watch all of this in the Network panel of DevTools. Reload with the panel open and you see the HTML request first, then the stylesheets, scripts and images it pulled in, each with its status and timing.

<head>
  <link rel="stylesheet" href="/css/site.css">
  <script src="/js/menu.js" defer></script>
</head>
FigureThree steps: the bakery's HTML text with an h2, a p and an a is parsed into a DOM tree under body, which the browser then lays out and paints as a heading, a paragraph and a link.Three steps: the bakery's HTML text with an h2, a p and an a is parsed into a DOM tree under body, which the browser then lays out and paints as a heading, a paragraph and a link.
The browser reads your text top to bottom and builds a tree of elements, the DOM, before it draws anything. The heading looks bold because of default styles; the h2 tag is what says it is a heading.

What is the DOM and why does it matter?

The parser turns your text into the Document Object Model, a tree of objects in memory. The <html> element is the root, <head> and <body> are its children, and every paragraph, link and list item hangs somewhere below. Text between tags becomes text nodes in the same tree.

CSS selectors match against this tree, and JavaScript reads and changes it with methods like document.querySelector(). When a script adds an item to a shopping basket, it is editing the DOM, and the browser redraws the part that changed. Your HTML file stays exactly as it was on the server.

The browser also builds an accessibility tree from the DOM. It holds each element's role (button, link, heading), its accessible name and its state. Screen readers and voice control software read this tree, which is why choosing <button> over a clickable <div> changes what a blind user hears.

<ul id="basket">
  <li>Sourdough loaf</li>
</ul>
<script>
  const li = document.createElement("li");
  li.textContent = "Rye rolls (6)";
  document.querySelector("#basket").append(li);
</script>

Why does the browser fix broken HTML instead of showing an error?

The HTML parsing rules in the Living Standard define exactly what to do with every mistake. A missing </p> is closed for you. A <div> inside a <p> ends the paragraph early. A table cell outside a table is dropped or moved. Every modern browser follows the same rules, so the same broken file produces the same tree in Chrome, Firefox and Safari.

The downside is silence. A typo will not produce an error message, and the page may look fine while the tree underneath is different from what you intended. Styles then miss their targets, or a screen reader announces a list as plain paragraphs.

Run important pages through the W3C Nu HTML Checker at validator.w3.org/nu. It reports the same problems the parser silently repairs, with line numbers.

Why does View Source differ from the Elements panel?

View Source (Ctrl+U or Cmd+Option+U) shows the bytes the server sent. The Elements panel in DevTools shows the live DOM after parsing, error recovery and any JavaScript changes. On a static page the two look almost the same. On a page built by a framework such as React, View Source may show an almost empty <div id="root"></div> while the Elements panel is full of content.

Use View Source to see what search engine crawlers and link previews receive first. Use the Elements panel to debug what is on screen right now. If a heading appears in Elements but not in View Source, JavaScript created it, and anything that does not run JavaScript will miss it.

How do HTML, CSS and JavaScript divide the work?

HTML says what things are. CSS says how they look. JavaScript says what happens when someone interacts. Keeping them separate makes each easier to change. A designer can restyle the bird club's event list without touching its markup, and a developer can add a filter script without rewriting the CSS.

The layers also fail gracefully in order. If the CSS file fails to load, the HTML still reads top to bottom as a plain document. If JavaScript is blocked or crashes, real links still navigate and real forms still submit. A page built on <a href> and <form action> keeps working; a page where every link is a <div onclick> stops dead.

Use HTML for anything that should exist without scripts: content, navigation, forms. Reach for JavaScript when you need something HTML cannot express, such as live filtering or saving a draft.

<form action="/search" method="get">
  <label for="q">Search birds</label>
  <input id="q" name="q" type="search">
  <button>Search</button>
</form>

How do you check that your HTML is doing what you think?

A few quick checks catch most problems:

  • Open DevTools, right-click an element and choose Inspect. Compare the tree with your source and look for elements the parser moved or closed early.
  • Open the Accessibility pane in the Elements panel to see each element's role and accessible name.
  • Press Tab from the top of the page. Every link, button and form control should receive focus in a sensible order with a visible outline.
  • Disable CSS (Firefox: View, Page Style, No Style) and read the page. If it still makes sense as a document, your structure is sound.
  • Paste the URL or file into the Nu HTML Checker and fix errors before warnings.

What should you look for when an AI tool writes your HTML?

AI-generated markup usually looks tidy and often hides the same few problems. Watch for clickable <div> and <span> elements with onclick handlers where a <button> or <a href> belongs. Look for headings chosen by size, so a page jumps from <h1> to <h4>, and for <br> tags stacked to create spacing that belongs in CSS.

Check for invented attributes. Tools sometimes produce things like <img alt-text="..."> or <input type="phone">. The browser ignores unknown attributes and falls back on unknown input types without telling you. Validate the output and test it with the keyboard before you ship it, exactly as you would with code from a new colleague.

Field notes

  • HTML uses tags to tell the browser what each part of a page is.
  • The browser builds a tree called the DOM from your HTML text.
  • HTML describes content, CSS styles it, and JavaScript adds behaviour.
  • Each paragraph of text goes inside its own <p> element.

Easy to get wrong

HTML should say what content means. Size is a styling decision for CSS, and <big> is obsolete.

Line breaks in the source collapse into a single space when rendered. Use <br> or separate paragraphs.

View Source is the raw file. The Elements panel shows the live DOM after error recovery and script changes.

A div cannot receive keyboard focus and has no button role, so keyboard and screen reader users cannot use it. A button gives you focus, Enter and Space activation, and the correct role for free.

Heading levels describe the outline of the page. Pick the level by structure and adjust the size in CSS.

Questions people ask

Is HTML a programming language?

No. HTML is a markup language. It describes content and structure but has no logic, conditions or loops. Programming on the web is done with JavaScript.

What version of HTML should I learn?

Learn the HTML Living Standard. There is no HTML6 coming; the standard is updated in place, and browsers follow it continuously.

Do I need special software to write HTML?

Any plain text editor works, and any browser can open the result. A code editor such as VS Code adds helpful highlighting and autocompletion.

What is the difference between HTML and the DOM?

HTML is the text you write. The DOM is the tree of objects the browser builds from that text and keeps in memory while the page is open.

Why does my page look different in two browsers?

Parsing is identical, but default stylesheets differ slightly in margins, fonts and form control styling. A small CSS reset or explicit styles for headings, lists and form controls removes most differences.

Keep going