
In brief
Browsers repair broken HTML silently, which is why a page can look fine while the markup is wrong. The structure that matters is doctype, lang, charset, viewport and title.
HTML is a forgiving language, and that is exactly why markup bugs survive: the browser silently repairs what you wrote, so the page looks fine while the document is not what you think it is. This guide covers the structure a document actually needs, the parts that are optional but matter, and the mistakes that produce layout differences weeks later.
You can test every example in the UrsaKit HTML online tool, which renders your markup in a sandboxed preview as you type.
01The browser is forgiving, which is the problem
Feed a browser an unclosed <div>, a table with mismatched cells, or a paragraph nested inside another paragraph, and it will not error — it will guess. The HTML parsing algorithm is specified in detail precisely because that guessing must be consistent across browsers.
The practical downside is that the DOM you get is not always the DOM you wrote. A <p> inside a <p> closes the first paragraph, a <div> inside <table> gets moved outside it, and invalid nesting in <ul> becomes text nodes.
The only reliable way to see what you actually produced is to inspect the rendered DOM, not the source file. Every browser's developer tools show the parsed tree.
02The five lines every document needs
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Page title</title>
</head>
<body>
<h1>One heading, describing the page</h1>
</body>
</html>
Each line has a job that is invisible until it is missing:
<!doctype html>switches the browser out of quirks mode. Without it, box sizing, percentage heights and line height follow legacy rules.langtells screen readers which pronunciation to use and lets the browser hyphenate correctly. Use a real tag such aszh-Hantores.charsetmust come first in the head. Wrong or late charset turns every non-ASCII character into mojibake.viewportis what makes a page mobile-friendly; without it phones render at a simulated 980-pixel width.titleis the label in tabs, bookmarks and search results.
One h1 per page.
The h1 is the page's subject. If every section starts with an h1, neither search engines nor screen reader users can tell what the page is about. Use h2 for sections and h3 for subsections inside them.
03head versus body
The head contains information about the document; the body contains what the user sees. Mixing them is one of the most common sources of confusion.
| Belongs in head | Belongs in body |
|---|---|
title, meta, link | h1–h6, p, ul |
style for the whole page | Elements the user reads or clicks |
script with defer | script at the end of the body |
| Favicon and preload hints | template and noscript fallbacks |
Content placed in the head is not rendered; markup placed in the body that belongs in the head is moved or ignored. If a stylesheet link seems to do nothing, check whether it ended up in the body.
04Void elements and escaping
Some elements have no content and no closing tag. They are called void elements, and writing </img> is a parse error even though browsers tolerate it.
<img src="/logo.png" alt="UrsaKit logo" width="1161" height="389" />
<input type="email" name="email" required />
<br />
<hr />
<meta charset="utf-8" />
Two rules cover most escaping bugs:
- Ampersands start an entity. Write
&for a literal&, otherwise&may begin a character reference and change the text. - Quotes inside attributes. Wrap attribute values in double quotes and escape inner double quotes as
", or switch the attribute to single quotes.
Always set width and height on images. The browser reserves the space before the file loads, which prevents the layout shift that ruins reading position and Core Web Vitals.
05What semantic elements actually change
section, article, nav and div all render as blocks with no default style. Choosing between them does not affect pixels, so teams often give up and use div everywhere. That trade has real costs:
- Screen readers can jump between landmarks only when the markup defines them.
- Crawlers use headings and landmarks to work out which part of a page is the main content.
- Your own CSS and tests get selectors such as
nav ulinstead of.wrapper-3 ul.
| Element | Use it for |
|---|---|
header / footer | Page or section intro and closing content |
nav | A group of navigation links |
main | The single main content area, once per page |
article | Content that would make sense on its own |
section | A themed group with its own heading |
div | A container that exists only for styling |
06Seven markup mistakes worth fixing
| Mistake | What actually happens | Fix |
|---|---|---|
| No doctype | Quirks mode changes box sizing and height rules | Add <!doctype html> |
lang missing or wrong | Wrong pronunciation, wrong hyphenation | Set the real language tag |
| Charset not first in head | Non-ASCII text becomes mojibake | Put meta charset first |
<div> inside <table> | The div is moved outside the table | Use thead, tbody, tr, td |
Block element inside p | The paragraph closes early | Close the paragraph, then start the block |
script without defer in head | Parsing waits for the script to download and run | Add defer or move it to the end |
Duplicate id attributes | getElementById and label associations hit the first one | Keep ids unique |
07Test markup without a build step
- Paste a full document or a fragment — The HTML tool accepts both. A fragment is wrapped in a minimal document, so you can check a component in isolation.
- Watch the preview as you type — The preview renders in a sandboxed frame, so scripts run without touching the tool's own page.
- Compare against the DOM, not your source — When something looks wrong, inspect the element in the preview. Browsers repair markup, and only the parsed tree tells you what you built.
- Move to styling — Once the structure is right, take the same markup into the CSS playground to work on layout, or run behaviour against it in the JavaScript runner.
Keeping the structure correct from the start is cheaper than finding out later that a layout bug was an HTML bug.
Write markup and see the rendered result instantly in a sandboxed preview, with no build step.
HTML Online ToolFrequently asked questions
Do I still need to write the doctype?
Yes. Without it, browsers use quirks mode, where box sizing and line height follow legacy rules and layouts break in ways that are hard to trace.
Is the html, head and body structure optional?
The browser inserts them if you omit them, but write them explicitly. Implicit elements are invisible in your source, which makes debugging slower than typing four extra tags.
What does the lang attribute change?
It tells screen readers which voice to use, tells the browser how to hyphenate and quote, and helps search engines understand the page language.
Where should a script tag go?
In the head with defer, or at the end of the body. A plain script tag in the head blocks parsing until the file has downloaded and run.
Are self-closing tags valid in HTML?
The trailing slash is ignored for void elements such as img or br, so img src="x" / is valid but meaningless. On non-void elements it is a parse error.
Does semantic markup change how the page looks?
No. section, article and div render identically. Semantics change what assistive technology and crawlers understand, and give CSS and JavaScript meaningful hooks.
Related articles
- How to center a div with CSS
The layout half of the same page you are marking up.
- Create a QR code that scans every time
What happens when markup and print sizes disagree.
Related tools
- HTML Online Tool
Render markup in a sandboxed preview.
- CSS Playground
Style the same markup in real time.
- JavaScript Runner
Run scripts against the page you built.
- Regex Tester
Find the markup you need to fix.