Text content
Headings, lists, emphasis, code — the elements that carry your prose, and the distinctions that matter.
Most of the HTML in any document is text inside text-flavored elements. Get the prose elements right and the page reads well in a browser, in reader mode, in a screen reader, and in the search-engine snippet that probably mattered most. Get them lazy — <div>s and <br>s scattered through paragraphs — and every downstream tool has to guess.
Headings — the spine
<h1> through <h6> mark headings of decreasing rank. They aren't sized text; they're structure. The browser's default styles happen to make <h1> big and <h6> small, but that's a side effect of meaning, not the meaning itself.
Two rules cover most of the craft:
- One
<h1>per page, identifying what the whole page is about. (Inside<article>you can have a second h1 for the article — sectioning content scopes the outline — but the conservative habit is one per document.) - Don't skip levels going deeper. A
<h3>directly under a<h1>reads as a missing section. Going up is fine — closing one h3 and starting a new h2 is normal — but<h1>followed by<h3>is a hole.
<h1>HTTP caching</h1> <h2>How browsers cache</h2> <h3>Memory cache vs disk cache</h3> <h2>How CDNs cache</h2>
A screen-reader user can navigate by heading the way you navigate by scrollbar — H to next heading, 2 to next h2. A page that uses <div class="title"> instead of <h2> is invisible to that workflow.
Paragraphs and emphasis
<p> wraps a paragraph. It has one rule worth remembering: a <p> can't contain block-level elements. Drop a <div> or <table> inside one and the parser implicitly closes the paragraph at that point — your DOM ends up with two adjacent paragraphs and a sibling, not a paragraph with a div inside.
For inline emphasis, HTML has two pairs that look interchangeable but aren't:
<em>and<strong>carry meaning.<em>says "the stress here changes the sentence" — the screen reader will read it with extra emphasis.<strong>says "this is important" — also read with emphasis.<i>and<b>carry presentation.<i>is for content that's typographically offset — book titles, foreign-language phrases, technical jargon on first use.<b>is "bring the eye here" — keywords in a UI, the lead sentence of a paragraph — without semantic emphasis.
If you're not sure, default to <em>/<strong>. The italics-and-bold-without-meaning cases (<i>/<b>) are real but narrower.
<p>The browser is <em>famously</em> forgiving — it has to be.</p> <p>Reading <i>The C Programming Language</i> changed how I think about computers.</p>
readFile in monospace because it's code, not because the word is more important than its neighbors. Which fits best?Lists
Three list types, each for a different shape of data:
<ul>— unordered list. Bullets. The order of items doesn't matter to the meaning. Reorder them and nothing changes.<ol>— ordered list. Numbers (or letters, withtype="a"). Order matters: step 2 follows step 1. Usestart="N"to begin from a different number; usereversedto count down.<dl>— description list. Pairs of<dt>(term) and<dd>(description). For glossaries, key-value displays, FAQs.
<ol> <li>Open the editor</li> <li>Save the file as .html</li> <li>Open the file in a browser</li> </ol> <dl> <dt>HTML</dt> <dd>HyperText Markup Language</dd> <dt>CSS</dt> <dd>Cascading Style Sheets</dd> </dl>
Lists nest. A <ul> inside another <ul> is fine — the indentation makes the nesting obvious. A <li> can contain block content (paragraphs, more lists, code blocks); unlike <p>, it doesn't get implicitly closed by what's inside it.
The instinct to use <br> to separate items in a "list" is a smell. Whenever you find yourself writing item one<br>item two<br>item three, that's a <ul> waiting to happen.
Quotes and code
<blockquote> is for a multi-line quotation set off from the surrounding text. It's a sectioning root, so headings inside it don't leak into the document outline. Use the cite attribute to point at the source URL.
<q> is for a short inline quotation. The browser adds the quotation marks for you — don't type them in addition, or you'll get nested quotes.
<blockquote cite="https://example.com/spec"> <p>The element represents content that is quoted from another source.</p> </blockquote> <p>The spec calls this <q>a flow content element</q>.</p>
For code, four elements with overlapping but distinct jobs:
<code>— a fragment of code inline in prose. Renders monospace by default.<pre>— preformatted text. Whitespace is preserved instead of collapsed. Pair with<code>for code blocks:<pre><code>...</code></pre>.<kbd>— keyboard input the user should type or press.<kbd>Cmd</kbd>+<kbd>K</kbd>.<samp>— sample output from a program or system. The flip side of<kbd>.
Most projects use only <code> and <pre><code>; <kbd> and <samp> are worth reaching for in technical writing where the distinction helps the reader.
npm test; the terminal prints 5 passing. Press Ctrl+C to exit." Which markup carries the most information?Smaller workhorses
A handful more, worth a sentence each:
<mark>— highlights text as relevant in a particular context. Search-result snippets use it to highlight the matched terms.<abbr title="...">— wraps an abbreviation. Thetitleprovides the expansion.<time datetime="...">— a date, time, or duration. The machine-readabledatetimeattribute lets crawlers parse the value (2025-04-26,PT2H30M) without trying to read the human-friendly text.<ruby>,<rt>,<rp>— for ruby annotations: pronunciation guides above the base text, common in CJK typography.<ruby>漢字<rt>kanji</rt></ruby>shows "kanji" hovering above the characters.<small>— fine print, side comments, legalese. Not for "smaller text" generically — that's a CSS concern.<cite>— the title of a creative work referenced inline (a book, paper, song). Italic by default.
These are the long tail. You won't reach for them every day, but knowing they exist means when one fits, you don't fall back on a <span> plus a class.