Chapter 2 — HTML in Depth: Document Structure
Section 1 — Why structure matters
Structure is the meaning underneath the visible page. When you write HTML, you are not only deciding what words appear on screen; you are telling the browser which words are a heading, which are a paragraph, which are navigation, and which are the main content. That meaning travels everywhere the page goes. A browser uses it to build the page, a search engine uses it to decide what the page is about, a screen reader uses it to let a blind visitor jump from heading to heading, and your own stylesheet uses it to style the right parts without fragile hacks.
Think of a page as a building. The visible paint, furniture and lighting are CSS and JavaScript, but the walls, rooms and corridors are HTML structure. You can repaint a room easily, but moving a wall after the building is finished is expensive. In the same way, adding a proper heading, a main landmark or a list after a page is styled usually means reworking selectors, breaking layouts and retesting the whole page. Getting structure right first is therefore not a matter of tidiness; it is a matter of saving time and avoiding rework.
Structure also decides how a page behaves when something goes wrong. A well-structured page still reads sensibly when its stylesheet fails to load, when JavaScript is blocked, when it is printed, or when it is read aloud line by line. Its headings still form an outline, its paragraphs still separate ideas, and its links still lead somewhere useful. A page built from meaningless containers, by contrast, collapses into one long undifferentiated stream of text in those situations.
A common mistake is to judge structure by appearance alone. If a piece of text looks like a heading because it is large and bold, a beginner may assume it is a heading. The browser does not care how it looks; it cares which element wraps it. A paragraph styled to look large is still a paragraph to a screen reader, so it will not appear in a heading list, and a search engine will not treat it as a topic label. The reverse mistake is equally common: using a heading element purely to make text big, even though the text is not a heading in the document's outline. Both mistakes make the page lie about itself. The rule to carry forward is simple: choose the element that describes what the content is, and let CSS decide how it looks.
Another way to test your structure is to strip the page down. Turn off styles in your mind, or use a browser's reader view, and ask whether the page still makes sense. Can you tell where the introduction ends and the details begin? Can you find the navigation without hunting through paragraphs? Can you tell which block is the article and which is a sidebar? If the answers are yes, your structure is doing its job. If not, the problem is rarely a lack of styling; it is a lack of meaning. This chapter teaches you to build that meaning deliberately, section by section, so that everything you add later rests on a solid foundation.
Check: Name three things that rely on a page's structure.
Section 2 — A complete document, revisited
Every HTML document follows the same skeleton, and understanding each bone in that skeleton prevents a whole class of beginner errors. The document begins with a doctype declaration, which is not an element but an instruction telling the browser to use standards mode rather than an older, inconsistent rendering mode. Without it, browsers may fall back to quirks mode, where sizing and layout behave in surprising, browser-specific ways. The doctype in modern HTML is deliberately short — <!DOCTYPE html> — because it no longer needs to name a particular version of the language. Its job is simply to say: treat this as modern HTML.
Inside the doctype sits the root element, <html>, which wraps everything else on the page. It is the parent of exactly two children: <head> and <body>. The head is the page's metadata compartment. Nothing inside the head is rendered as visible content; instead, it holds information about the document, such as its title, its character encoding, its description for search engines, and links to stylesheets and scripts. Beginners sometimes put visible content in the head by accident, or put metadata in the body, and both mistakes confuse browsers. Keeping the split clean — metadata in the head, visible content in the body — makes the document predictable.
The body is where the page lives for the visitor: headings, paragraphs, images, links, forms and everything else a person can see or interact with. Inside the body you will build the semantic skeleton this chapter covers: a header, navigation, a main region, sections, articles, asides and a footer. Those elements are not required by the HTML parser in the way head and body are, but they are what turn a technically valid document into a genuinely well-structured one. A document with only head and body and a pile of divs will render, but it will not communicate its shape to anyone except a sighted reader.
A complete real-world document also needs a few pieces that Chapter 1 only hinted at. The html element needs a language attribute, the head needs a character encoding declaration placed early, a title, a viewport declaration for mobile devices, and a description for search results. None of these is decoration. The language attribute affects pronunciation in screen readers and automatic translation. The encoding declaration prevents garbled characters. The viewport declaration prevents mobile browsers from shrinking the page. The title is what appears in tabs and bookmarks. Leaving any of them out does not stop the page from loading, but it quietly degrades the experience for a large group of visitors.
It helps to write this skeleton from memory, without copying it, until it feels automatic. Start with the doctype, open html with its language, open head, add charset, title, viewport, description and stylesheet link in a consistent order, close head, open body, build your semantic structure, and close body and html. Following the same order every time means you will notice immediately when something is missing, and other developers reading your code will know where to look. That habit — a consistent, complete skeleton for every page — is one of the clearest signs that a beginner is becoming a reliable front-end developer.
Check: What four parts does every HTML document have?
Section 3 — The lang attribute
The lang attribute on the html element declares the primary language of the page, for example <html lang="en"> for English, <html lang="fr"> for French, or <html lang="ha"> for Hausa. It looks like a minor detail, and it is easy to leave out or to leave at a default value when you copy a template, but it has real consequences for people and for machines. Screen readers use it to choose the correct pronunciation rules. A French sentence read with English pronunciation rules becomes difficult or impossible to understand, and the same is true in reverse. Translation tools, spell checkers, search engines and text-to-speech systems all take their cue from this attribute, so getting it wrong misleads every one of them at once.
Language codes follow a standard system, and you should use the correct code rather than inventing one. The main code is usually two letters, such as en, fr, yo for Yoruba, ig for Igbo, or ha for Hausa, and it can be extended with a region where that matters, such as en-GB for British English or en-US for American English. If your page is written in Nigerian Pidgin, there is no need to force it into a code that does not fit; use the closest accurate declaration and be consistent.
A page can also contain passages in a different language from the main one, and HTML handles that gracefully. You can set lang on a smaller element, such as a paragraph or a span, to override the page language for that passage only. For example, a mostly English article that quotes a French proverb should mark that quotation with lang="fr", so a screen reader switches pronunciation for those words and then switches back. The same principle applies to proper names in another language, although very short names inside a sentence are a judgement call and do not always need marking.
The most common mistake is copying a template and never changing its lang value. A page written in French but marked en, or a page written in Yoruba but marked en because the template said so, is a silent accessibility failure: nothing looks wrong on screen, but the spoken version is wrong. Another mistake is setting lang on the body instead of the html element, or setting it inconsistently across pages on the same site. The declaration belongs on html, it should match the actual language of the page's main content, and it should be checked whenever a page is translated or repurposed. Those three checks take seconds and prevent a problem that visitors may never be able to report clearly, because they may simply experience the page as confusing or broken without knowing why.
When you are unsure which code to use, look it up rather than guessing, and test the result if you can: many screen readers and browsers will show or announce the language they have detected. Treat lang as part of the document's identity, not as boilerplate. A page that correctly declares its language respects its readers, helps search engines place it for the right audience, and gives every automated tool that touches the page a correct starting point. That is a large return for a single short attribute.
Check: What breaks if a French page is marked lang="en"?
Section 4 — Character encoding
Character encoding is the agreement between your file and the browser about how the bytes in the file should be turned into characters on screen. A text file is stored as numbers, and an encoding is the table that maps those numbers to letters, symbols and characters from different writing systems. If the browser uses a different table from the one the file was saved with, the same numbers decode into the wrong characters, and you get the classic symptom of garbled text: replacement symbols, question marks, or letters from the wrong script appearing where your content should be. The declaration <meta charset="utf-8"> tells the browser to use UTF-8, the encoding that covers almost every modern language and symbol set in a single table.
UTF-8 is the right default for the modern web for several practical reasons. It can represent English, French accents, Arabic script, Chinese characters, Yoruba and Igbo characters with tone marks, emoji, currency symbols and mathematical symbols, all in the same document, without switching tables. UTF-8 removes that trade-off, which is why it is now used by the overwhelming majority of pages. Unless you have a specific legacy reason to use something else, and you almost certainly do not, UTF-8 is the correct choice for every new page.
Placement matters as much as the declaration itself. The charset meta tag should be the first thing inside the head, or at least within the first part of the head, because the browser needs to know the encoding before it starts reading the rest of the document, including the title. The habit to form is therefore rigid: open head, write the charset line first, then everything else. That ordering costs nothing and removes an entire category of subtle bugs.
Encoding problems also have a second source that the meta tag alone cannot fix: the file itself must actually be saved as UTF-8. Most modern editors save as UTF-8 by default, but if an editor is set to another encoding, the bytes in the file will not match what the declaration promises, and the browser will still show garbled characters even though the HTML looks correct. If you ever see garbled text on a page whose charset declaration looks right, check the editor's save encoding before assuming the HTML is wrong. Similarly, a web server can send its own encoding header, and that header overrides the meta tag, so a mismatch between server and document can also cause trouble. In that case the fix belongs on the server configuration, not in adding a second declaration.
For a beginner, the practical rules are short. Always include <meta charset="utf-8"> as the first element in the head. Always save your files as UTF-8. Test with characters beyond plain English — an accented letter, a naira sign, a character from another script — early in a project, so an encoding problem shows up while it is still easy to fix. A page that handles characters correctly is not a luxury; it is a basic requirement for a web that serves readers in every language, and UTF-8 plus correct placement is how you meet it.
Check: What symptom suggests a page has the wrong character encoding?
Section 5 — The title element
The <title> element sits in the head and gives the document its name. It does not appear as a heading inside the page itself; instead, it appears in places that surround the page: the browser tab, the window title, the bookmark name when a visitor saves the page, the history list, and the clickable headline in search results. Because it appears in so many places where the page itself is not visible, the title often does the job of persuading someone to open, return to, or trust the page before they have seen any of its content.
A good title names the specific page, not just the site. "Pricing — Kelick Tech Hub" tells a visitor exactly what they will find and distinguishes the page from every other page on the same site. "Home", "Untitled Document" or the site name alone tells them almost nothing, and it creates a practical problem as well: when several tabs share the same vague title, a visitor cannot tell them apart, and when several pages share the same title in search results, a search engine cannot tell them apart either. Each page deserves its own title, written for that page's content, with the most distinctive words first so that they survive truncation in narrow tabs and search listings.
Length is a judgement, not a strict rule, but a useful guide is to keep titles concise enough to be read at a glance — roughly under sixty characters where possible — while still being specific. Front-load the page-specific words and put the site name at the end, separated by a dash or a vertical bar, so that the part a visitor most needs to recognise appears first. Write the title the way you would name a chapter: informative, honest and readable on its own.
There are a few mechanical details to get right. A document must have exactly one title element, and it must be inside the head. The title cannot contain other HTML elements; it is plain text, so any markup inside it will be treated as text or cause a validation error. Special characters such as an ampersand still need to be written as entities inside the title, just as they do elsewhere. If a title is missing entirely, browsers will fall back to showing the file name or the address, which is almost always less helpful than a written title, and some validators and accessibility checks will flag the omission as an error.
When you are deciding on a title, imagine it out of context. Would it make sense in a list of bookmarks, in a search results page, or in a row of open tabs where only the first words are visible? Would it still be accurate if the page content changed slightly? Would a visitor who found it through search feel that the page delivered what the title promised? If the answer to all three is yes, the title is doing its job. It is a small element with an outsized effect, because it is often the first and sometimes the only part of your page that a potential visitor ever reads.
Check: Where does a page's title appear to visitors?
Section 6 — The viewport meta tag
The viewport meta tag exists because mobile browsers made a decision, years ago, to pretend to be desktop browsers. Early smartphones had small screens but the web was built for desktop widths, so mobile browsers loaded pages at a wide virtual width — typically around 980 pixels — and then shrank the whole page to fit the phone screen. That made desktop layouts readable in miniature, but it made text tiny and forced visitors to pinch and zoom to read anything. The viewport tag tells the browser to stop pretending: use the device's actual width as the layout width, and start at a normal zoom level. The standard declaration is <meta name="viewport" content="width=device-width, initial-scale=1">, and it belongs in the head of every page that is meant to work on phones.
The two parts of that content value each do a distinct job. width=device-width sets the viewport width to the width of the device in CSS pixels, so a layout that adapts to width can respond to the real screen instead of an imaginary desktop one. initial-scale=1 sets the starting zoom to one hundred percent, so the page is not zoomed out when it first loads.
Without the viewport tag, even a well-designed responsive layout will fail on mobile, because the browser will never give it the narrow width it is designed for. Media queries that should trigger at phone widths will not trigger, text will render at desktop size and then be shrunk, and the page will look like a miniature desktop site. This is one of the most common reasons a beginner's site looks fine on a laptop but unusable on a phone, and the fix is a single line in the head. If you ever open a page on a phone and see tiny text with wide margins and a need to zoom, the missing viewport tag should be the first thing you check, before you blame your CSS.
The viewport tag does not by itself make a page responsive; it only gives responsive CSS a truthful starting point. You still need layouts that adapt, text that wraps, and images that scale, all of which later chapters cover. What the tag does is ensure that the browser and your CSS are talking about the same screen. Think of it as removing a distorting lens: the page underneath still needs to be well designed, but at least it is now being seen at its true size. Testing on a real phone, or in a browser's device mode, after adding the tag will show you the difference immediately, and it is a test worth running for every page you build.
A final habit is worth forming: include the viewport tag in your skeleton template alongside charset and title, so no page is ever published without it. Because it is a single line, it is easy to forget on a quick page, and because its absence only shows up on mobile, it is easy to miss if you only test on a desktop. Adding it by default, and checking mobile rendering as part of your normal workflow, closes that gap for good.
Check: What does a missing viewport tag look like on a phone?
Section 7 — Meta descriptions
A meta description is a short summary of a page, written in the head as <meta name="description" content="...">, for search engines and other tools that need to describe the page without reading the whole of it. When a search engine shows your page in its results, it often uses your description as the snippet of text beneath the clickable title. That snippet is frequently the deciding factor in whether a person clicks: a clear, specific description that matches what they searched for invites a click, while a vague or missing description leaves the search engine to guess, usually by pulling a random sentence from the page that may not represent it well at all.
The description should describe this page, not your whole site. A common beginner mistake is to copy the same description onto every page — a general statement about the site — so that every search result for the site shows the same snippet, no matter which page it points to. That wastes the chance to tell a searcher why this particular page answers their question. Instead, write a fresh description for each page, naming its specific topic, its audience, or the problem it solves, in plain language that a human would actually read. If the page is a pricing page, say what pricing it covers; if it is a tutorial, say what the reader will learn.
Length matters because search engines truncate long snippets. A useful guide is to keep the description under about 160 characters, so that the whole summary is visible in most results without being cut off mid-sentence. Aim for one or two sentences, front-load the most important words, and avoid repeating the title word for word. The description and the title should complement each other: the title names the page, and the description explains why it is worth opening.
It is also important to understand what a meta description does not do. It is not a ranking trick: writing a description stuffed with keywords will not by itself lift a page in search results, and search engines may ignore or rewrite a description that does not match the page's actual content. It does not appear on the page itself, so visitors who are already on the page will never see it, and it is not a substitute for good content. Its job is narrower and still valuable: to represent the page accurately in the places where the page itself is not visible, so that the right people click through and the wrong people are not misled.
Write the description after the page content is finished, not before, so that it describes what the page actually says rather than what you intended it to say. Read it back as if you were a stranger scanning search results: does it tell you, in a second, what you will get if you click? Does it sound like a human summary rather than a slogan? If you can answer yes, the description is ready. It is a small piece of writing, but it is often the first piece of your page that a new visitor encounters, and it deserves the same care as a heading.
Check: How long should a meta description be, roughly?
Section 8 — Linking a stylesheet
An external stylesheet is a separate CSS file that a page loads with a link element in its head, for example <link rel="stylesheet" href="css/style.css">. The two attributes in that example each carry a distinct piece of information, and confusing them is a common beginner error. The rel attribute describes the relationship between the current document and the linked resource — in this case, that the linked file is a stylesheet for this page. The href attribute gives the location of that resource, as a path the browser can follow to fetch it. One says what the file is for; the other says where to find it. If either is wrong, the styles will not load, and the page will appear unstyled.
Keeping CSS in an external file, rather than writing it inside each page, is one of the most valuable habits in front-end work. A single stylesheet can be shared by every page on a site, so changing a colour, a font or a layout rule in one place updates the whole site at once. External files are also cached by browsers, so after a visitor's first page, later pages load faster because the stylesheet does not need to be downloaded again. Those two benefits — one source of truth and better performance — are why external stylesheets are the default for real sites.
The href path follows the same relative-path rules as links and images, and it is read from the location of the HTML file, not from the site root unless you say so. A page in the site root linking to css/style.css expects a css folder next to it. A page inside a subfolder that uses the same path will look for a css folder inside that subfolder and fail, unless it steps up a level with ../css/style.css or uses a root-relative path beginning with a slash.
Order matters when a page loads more than one stylesheet. Stylesheets are applied in the order their link elements appear, and when two rules conflict, the later one generally wins if they have equal specificity. That ordering is a tool: a base stylesheet can set site-wide defaults, and a page-specific stylesheet loaded after it can override just the rules that need to differ. Keeping link elements in a deliberate, documented order — base first, then components, then page-specific — prevents that confusion.
A few details complete the picture. The link element is empty: it has no closing tag and no visible content, because its job is to fetch a resource, not to display anything. It belongs in the head, so that styles are available before the browser renders the body and visitors do not see a flash of unstyled content. The rel value must be exactly stylesheet for a CSS file; a typo there means the browser will fetch the file but not treat it as styles. Check those three things — correct rel, correct path, correct position in the head — whenever styles do not appear, and you will solve most stylesheet problems in minutes.
Check: What do rel and href each mean in a link element?
Section 9 — Loading scripts the right way
JavaScript can change a page, respond to visitors and fetch data, but how a script is loaded decides whether it helps or harms the first impression of a page. By default, when a browser meets a script element while parsing the HTML, it stops parsing, fetches the script if it is external, runs it, and only then continues. Understanding that blocking behaviour is the key to loading scripts well.
The simplest traditional fix is to put most scripts at the end of the body, just before the closing body tag. By that point the browser has already parsed the visible content, so the page can render before the script is fetched and run. This works well for scripts that enhance a page after it appears, and it is still a valid approach. For small sites that trade-off is often acceptable, but it is not the only option.
The modern preferred option for scripts in the head is the defer attribute, as in <script src="app.js" defer></script>. A deferred script is downloaded in parallel while the browser continues parsing the document, but it does not run until parsing is complete, and deferred scripts run in the order they appear in the document. That combination gives you the best of both approaches: early discovery and download, no blocking of rendering, and predictable execution order for scripts that depend on each other. For most page scripts that need the full document to exist before they run — which is most of them — defer is the right default, and it is what you should reach for first.
There is also an async attribute, and it is important not to confuse it with defer. An async script is also downloaded in parallel and does not block parsing, but it runs as soon as it finishes downloading, even if parsing is not complete, and async scripts do not guarantee order relative to each other. That makes async suitable for independent scripts that do not depend on the document being complete or on other scripts — analytics and advertising scripts are typical examples — but unsuitable for a main application script that expects the whole page to be present. Choosing between defer and async is therefore a question about dependencies: if the script needs the document or another script, defer; if it is truly independent, async may be appropriate.
A common mistake is to add both defer and async, or to use defer on an inline script, where it has no effect because there is nothing to download. Another is to assume that defer fixes a script that runs before its elements exist: defer guarantees the document has been parsed, but it does not guarantee that other deferred scripts or dynamically added content are ready, so code should still check for the elements it needs. The practical rule for this chapter is short: put page scripts in the head with defer, reserve async for independent third-party scripts, and keep the old end-of-body pattern as a fallback you understand rather than a habit you follow blindly. Loaded this way, JavaScript enhances a page that already works, instead of holding it hostage.
Check: What does defer do, in plain words?
Section 10 — Comments in HTML
An HTML comment is text inside <!-- and --> markers that the browser ignores when rendering the page. Visitors never see it, search engines do not treat it as content, and screen readers do not announce it. Its audience is entirely human: the next developer who reads the file, including yourself in six months' time. Used well, a comment explains something that the code alone cannot explain, such as why a section is structured an unusual way, why a workaround exists, or where a block of content comes from. Used badly, it adds noise that makes the file harder to read without adding understanding.
The most useful comments explain why, not what. A comment that says <!-- Main navigation --> above a nav element adds almost nothing, because the element itself already says that. A comment that says why the navigation is duplicated for a particular page, or why a certain landmark is placed where it is, saves the next reader from guessing or from "fixing" something that was deliberate. The same rule applies to workarounds: if you have used a particular structure because of a known browser behaviour or a requirement from another system, a short comment recording that reason prevents someone from removing the workaround in a tidy-up and reintroducing the bug. Comments are, in that sense, a record of decisions, not a narration of code.
There are also things comments must not be used for. They should not contain sensitive information, such as passwords, private addresses, internal notes about a person, or anything you would not want a visitor to discover, because comments are sent to the browser with the page source and anyone can view them with "View Source" or developer tools. Beginners sometimes assume that because a comment is invisible on the rendered page, it is private; it is not. Similarly, comments should not be used to hide large blocks of old code indefinitely. Old code belongs in version control, not in comments.
Technically, a comment must not contain a double hyphen inside it, because -- can confuse the parser about where the comment ends, and a comment should be closed properly or everything after it may be swallowed. Nested comments are not supported: you cannot put a comment inside another comment and expect both to work. Keeping comments short, single-purpose and properly closed avoids those traps. It also helps to place a comment on its own line directly above the block it describes, rather than at the end of a long line where it may be missed or may push the line beyond a readable width.
Finally, remember that comments are a courtesy, not a substitute for clear code. If a structure needs a long comment to be understood, that is often a sign that the structure itself could be clearer — better element choices, better indentation, or a simpler arrangement. Write the clearest code you can first, then add comments only where a future reader would still have a genuine question. A file with a few well-chosen comments reads like a guided tour; a file covered in comments reads like a page that is apologising for itself.
Check: Do HTML comments appear on the rendered page?
Section 11 — Nesting rules
Nesting is the parent-and-child relationship between elements, and the rule is simple: an element opened inside another element must be closed before its parent closes. The correct form <p><strong>bold</strong></p> shows the strong element fully contained inside the paragraph, like a box inside a box. The incorrect form <p><strong>bold</p></strong> crosses the boundaries, as if the inner box stuck out through the wall of the outer one. Browsers will not refuse such a page; they will guess what you meant and repair it, but different browsers may repair it differently, and the repaired structure may not be the one your CSS or JavaScript expects.
That silent repair is why nesting errors are so troublesome. A page can look correct while its underlying tree is wrong, so a style that should apply to a bold word inside a paragraph may apply elsewhere, or a script that looks for an element inside a particular parent may fail to find it. The error is invisible until something else breaks, and by then the cause is far from the symptom. Validating your HTML catches these crossings immediately, which is why the validator habit in Section 42 matters. Indentation helps too: if your closing tags do not line up with their opening tags in a way that mirrors the nesting, something is probably crossed.
Some elements have additional nesting rules beyond the general principle. A paragraph cannot contain a block element such as a heading, a list or another paragraph; if you try, the browser will close the paragraph early and the block will end up as a sibling, not a child. A link cannot contain another link, and a button cannot contain a link or another button, because interactive content inside interactive content creates ambiguity about what a click should do. Lists have their own rule: only list items may be direct children of a list element, so any paragraph or link inside a list must sit inside a list item first. Learning these specific rules saves you from structures that look plausible in source but are invalid in the document tree.
A practical way to check nesting is to read a block aloud as pairs: open paragraph, open strong, close strong, close paragraph. If the pairs close in reverse order of opening — last opened, first closed — the nesting is correct. If you ever find yourself closing an outer element while an inner one is still open, stop and reorder the tags. Editors with automatic tag closing and bracket matching make this easier, but the habit of checking the order yourself is what protects you when an editor's guess is wrong. Correct nesting is not pedantry; it is the guarantee that the tree the browser builds is the tree you intended. A validator or a browser's element inspector will show you the repaired tree, which is often the fastest way to see that a crossed nesting error has changed the structure you intended.
Check: Which of the two examples above is correctly nested?
Section 12 — Block versus inline, first look
Block and inline are the two basic display behaviours in HTML, and they describe how an element takes up space on a line. A block element, such as a paragraph, a heading or a list, starts on a new line and stretches to fill the full width available to it, pushing the next block onto a new line below. An inline element, such as a link or a bold span, does not start a new line; it sits inside the flow of text, taking up only as much width as its content needs, and allows text to continue on either side of it. That single distinction explains most of what you see when a page first renders without any CSS.
The distinction is about default behaviour, not about what an element is allowed to contain. Block elements generally contain other blocks and inline elements, while inline elements generally contain only text and other inline elements. A paragraph can contain a link, bold text and an image, but a link should not contain a whole paragraph or a heading in classic HTML usage, because an inline container is not meant to hold a block-sized structure. When beginners ignore that rule, browsers often repair the page by splitting the inline element around the block, producing a tree that surprises both CSS and JavaScript. Knowing which category an element belongs to therefore prevents a class of layout surprises before CSS is even involved.
It is also important not to confuse the HTML category with the CSS display property. CSS can change how an element displays — a list item can be made inline, a span can be made block — and later chapters will use that power extensively for navigation menus and layouts. Changing the display does not change the element's meaning, however. A paragraph displayed inline is still a paragraph to a screen reader, and a span displayed as a block is still a meaningless container. The HTML category tells you what the content is; CSS tells you how it should look in a particular design. Keeping those two jobs separate is what makes a page both meaningful and flexible.
For layout decisions, the block-versus-inline idea gives you a quick mental test. If you want something to occupy its own line and push other content below it, you want a block. If you want something to sit inside a sentence or a paragraph without breaking the line, you want an inline element. When a layout does not behave as expected, ask first whether you have chosen the wrong category — for example, trying to set a width on an inline element, which by default ignores width, or expecting two block elements to sit side by side without CSS intervention. Most early layout frustrations trace back to that question, and answering it correctly is faster than adding CSS to fight the default. When you later set a link to display as a block for a larger click area, remember that its meaning as a link has not changed, even though its layout behaviour has.
Check: Does a paragraph start on a new line by default?
Section 13 — The header element
The <header> element marks introductory content for a page or for a section within it. At page level, a header typically contains the site logo or title, a tagline, and often the main navigation. At section level, a header contains the introduction to that section: its heading, perhaps a short summary, a date, or author information. The key idea is introduction, not position: a header is not defined by being at the top of the screen, but by introducing the content that follows it. That is why a page can legitimately have more than one header, one for the page as a whole and others for individual articles or sections.
A common misunderstanding is that header is a synonym for the head element. They are different things with similar names, and confusing them causes real errors. The head element, covered in Section 2, is invisible metadata about the whole document. The header element is visible content inside the body that introduces a page or a section. Another misunderstanding is that there can be only one header per page, by analogy with the main element. That restriction does not apply to header: the specification allows multiple headers, provided each one introduces a distinct sectioning context. An article with its own title and byline, for example, deserves its own header inside the article, even though the page already has a site header.
What belongs inside a header follows from its introductory role. Headings belong there, naturally, as does a logo, a brief description, and navigation that helps a visitor orient themselves. What does not belong there is the main content itself, or unrelated material that happens to sit near the top of the page. A hero image with a call to action might be part of a header if it genuinely introduces the page, but a long article body placed inside a header because it is near the top would misdescribe the content to screen readers, which announce headers as landmarks and let visitors jump to them. If removing the header wrapper would not change the meaning of the content, the wrapper may be unnecessary; if it clarifies what introduces what, it is doing its job.
When you use multiple headers, keep each one focused. A section header should contain only the introduction to that section, not a repeat of the site header, and an article header should contain the article's title and metadata, not the whole site navigation. Screen reader users navigate by landmarks, and a page cluttered with identical headers becomes harder, not easier, to navigate. Used with restraint, however, multiple headers make the page's structure explicit: the site header introduces the site, each section header introduces its section, and the visitor — sighted or not — can always tell where a new part of the page begins. An article header that includes the author and date also helps feed readers and search tools identify that article as a distinct, attributable item.
Check: Can a page have two header elements? When?
Section 14 — The nav element
The <nav> element marks a block of navigation links: a set of links whose purpose is to help a visitor move around a site or a document. The most common example is the main menu, with links to the home page, to major sections, and to contact information. Other examples include a table of contents for a long article, pagination links at the bottom of a list of results, and a breadcrumb trail showing where the current page sits in the site hierarchy. In each case, the links work together as a navigation aid, and wrapping them in nav tells browsers and screen readers that this block has that job.
Not every group of links qualifies, and overusing nav is a real problem. A paragraph that happens to contain a link, a list of related articles at the end of a post, or a set of social media links in a footer may be links, but they are not necessarily navigation in the landmark sense. The test is whether the block is a major navigation aid that a visitor would want to jump to directly. Screen readers offer a shortcut to jump between nav landmarks, and if a page has six or seven nav elements, that shortcut becomes useless because the visitor must step through minor link groups to find the main menu. Reserve nav for major navigation, and leave ordinary link groups unwrapped or inside a more appropriate element such as an aside.
When a page has more than one genuine nav block, distinguish them with an accessible label. An aria-label attribute, such as aria-label="Main navigation" for the primary menu and aria-label="Footer navigation" for the footer menu, lets a screen reader announce which navigation block the visitor has reached. Without labels, a visitor hears only "navigation" repeatedly and cannot tell them apart. This is a small addition with a large accessibility benefit, and it is worth adding whenever a second nav appears. The label should be concise and should describe the purpose of that navigation, not repeat the word navigation unnecessarily.
Inside a nav element, links are often organised as a list, because a menu is conceptually a list of destinations. That is a convention rather than a requirement, but it helps screen readers announce how many items the menu contains and lets visitors move through them systematically. Whether you use a list or not, the links themselves should be clear and descriptive on their own: "Pricing" is better than "Click here", because a visitor navigating by links alone hears the link text out of context. Good nav is therefore a combination of the right element, a clear label when there are several, and link text that makes sense without the surrounding sentences. If a table of contents is long, grouping its links under subheadings inside the nav can help visitors scan it, provided the list structure itself remains clear.
Check: Should every link on a page sit inside a nav element?
Section 15 — The main element
The <main> element wraps the primary content of a page — the content that is unique to this page and that the visitor came for. Everything repeated across pages, such as the site header, the main navigation, a sidebar that appears everywhere, and the footer, does not belong inside main. A page should have exactly one main element, and that uniqueness is what makes main useful: it gives browsers, search engines and assistive technology a single, reliable way to identify the heart of the page, distinct from the furniture that surrounds it on every page.
That single-main rule is enforced by more than convention. Screen readers provide a shortcut to jump straight to the main content, skipping repeated navigation and headers, and that shortcut only works sensibly if there is one destination. If a page had two main elements, the shortcut would have no clear target, and a visitor who wants to skip the menu would be sent to an arbitrary one. Similarly, search engines treat main content as more central to what the page is about than header or footer content, so placing repeated boilerplate inside main dilutes that signal. The rule is therefore not about tidiness; it is about giving the page one unambiguous centre.
A common mistake is to wrap the entire body, including header and footer, in main, because the beginner thinks of main as meaning "everything". That defeats the purpose: if main contains everything, it distinguishes nothing. Another mistake is the opposite — leaving the primary content outside main and wrapping only a small part of it, perhaps because a template was copied and the main tags were placed around a single section. Both errors are easy to make and hard to spot visually, because the page looks identical either way. The check is structural: read the page and ask, "If I removed everything that appears on every page of this site, what would remain?" The answer should be exactly what sits inside main, and nothing else.
Main is also distinct from the other landmarks. Unlike header and footer, which can appear several times for different sections, main is unique to the page. Unlike section and article, which describe the internal organisation of content, main describes the content's role relative to the whole page. You can therefore have a main that contains several sections and articles, each with its own headers, and the structure remains clear at both levels: main says "this is the page's content", and the sections inside say "this is how that content is organised". Keeping that hierarchy clean is one of the simplest ways to make a page navigable for everyone, including future developers who need to find where the real content lives. A skip link that points to the main element is a practical companion to this landmark, because it gives keyboard users a visible way to jump past repeated navigation.
Check: How many main elements should a page have?
Section 16 — Sections
A <section> groups related content under a heading, forming a thematic chunk of a page in the way a chapter forms a chunk of a book. A product page might have sections for description, specifications and reviews; a tutorial page might have sections for introduction, steps and troubleshooting. The heading is not optional decoration: it is what gives the section its identity. Without a heading, a visitor using a screen reader cannot tell what the section is about from its landmark alone, and the grouping loses much of its meaning. The practical rule is that if you cannot write a natural heading for the group, it is probably not a section.
That heading test also distinguishes section from its closest neighbour, the div. A div is a generic container with no meaning, used for grouping content for styling or scripting when no semantic element fits. A section, by contrast, asserts that its contents belong together as a theme and deserve to be listed in the document's outline. Using a section for a purely presentational wrapper — for example, wrapping a few elements solely so you can apply a background colour — misdescribes the page, because it adds an outline entry for something that is not a topic. Conversely, using a div for a genuine thematic chunk with a heading hides a real topic from the outline. The choice should follow the content, not the stylesheet. For example, a page about a city might have sections for history, transport and food, each with a clear heading that tells visitors exactly what that part covers.
Sections can nest, and they often do. A long article might be divided into sections, and one of those sections might itself contain subsections for finer topics. Each level should have a heading at the appropriate level in the outline, so the nesting of sections matches the nesting of headings. A section inside another section with a heading at the same level as its parent creates a confusing outline, even though the page may look fine. Reading the headings alone, as Section 22 recommends, is the best way to check whether your section nesting actually reflects the topics, or whether sections have been added for layout convenience.
Finally, remember that section is a general-purpose thematic container, not a substitute for a more specific element. If the grouped content is a self-contained article that could stand alone, article is more precise. If it is tangential content, aside is more precise. If it is introductory or closing material, header or footer may fit. Section is the right choice when the content is a distinct theme within a larger page and no more specific element describes it. Used that way, sections turn a long page from a wall of text into a navigable structure with clear, headed parts that a visitor can scan, jump between, and understand.
Check: What should a section always have that a div does not need?
Section 17 — Articles
An <article> marks a self-contained piece of content that would still make sense if it were lifted out of the page and published on its own. A blog post, a news story, a forum post, a product card and a comment are all classic examples, because each one has its own title, its own content, and its own completeness: you could syndicate it, share it, or read it in a feed without needing the rest of the page to understand it. That self-containment test — "Would this make sense alone?" — is the most reliable way to decide whether article fits, and it is more useful than asking whether the content merely looks like a card or a block.
Articles and sections are often confused because they can contain each other, and both group content. The difference is one of independence versus theme. A section groups related content under a heading within a larger whole; it is a part of something bigger. An article is a whole in itself, even if it happens to sit inside a larger page. A blog homepage, for example, contains several articles, each a complete post, and those articles might be grouped inside a section headed "Latest posts". Inside a single long article, by contrast, sections divide the article into headed parts, such as introduction, method and conclusion. The nesting can go either way, and the element you choose at each level should reflect whether that level is a part or a whole.
Choosing article correctly has practical benefits beyond correctness. Search engines and feed readers can treat articles as distributable units, which helps a blog post or news story be found and shared as an item in its own right. Screen readers can navigate between articles on a page, letting a visitor skip from one post to the next without wading through each one. Styling also becomes easier, because an article provides a natural boundary for a card or a post layout, with its own header and footer for title, author and date. None of those benefits requires extra code; they follow from choosing the element that already means "independent item".
A common mistake is to wrap every block in article simply because it looks like a distinct visual card. A pricing table, a testimonial carousel slide, or a sidebar widget may look like a card, but if the content only makes sense in the context of the page — for example, a single feature bullet from a product description — it is not self-contained and article overstates it. Another mistake is the opposite: leaving a genuine blog post as a plain div, which hides its independence from every tool that could use it. When in doubt, apply the lift-out test honestly, and choose article only when the content passes it. That restraint keeps the element meaningful instead of diluting it into another generic container.
Check: Give two examples of content that suit an article element.
Section 18 — Asides
An <aside> marks content that is related to the main content but separate from it — material that enriches the page without being part of its central argument or narrative. Typical examples include a sidebar of related links, a pull quote drawn from the article, a box of definitions, a short biography of the author, or an advertisement related to the topic. The defining feature is tangentiality: the aside is connected to the page, but the page would still be complete without it. If removing the content would break the main content's sense, it is not an aside; it belongs in the main flow.
The removal test is the simplest way to decide. Take the candidate block out of the page in your mind and read what remains. If the main article still reads coherently, with its argument intact and no missing step, the block was tangential and aside is a strong candidate. If the article now has a gap — a term used but never defined, a step skipped, a claim without its evidence — then the block was essential and should stay in the main content, even if it is visually set apart in a box. Visual separation alone does not make something an aside; many essential callout boxes are styled as side boxes but are part of the main content, and marking them as asides would tell a screen reader they can be skipped when they cannot.
Aside has two common placements, and both are valid. At page level, an aside is usually a sidebar: related posts, a tag list, or site-wide supplementary material that relates to the page as a whole. Inside an article, an aside is usually a smaller tangential block: a pull quote, a glossary note, or a related fact that belongs to that article specifically. The placement tells assistive technology what the aside relates to: an aside inside an article is understood as tangential to that article, while an aside outside main is understood as tangential to the page. Placing it thoughtfully therefore communicates scope, not just separation.
A frequent mistake is to use aside for any content that appears in a sidebar column, regardless of its relationship to the main content. A navigation menu in a sidebar is navigation, not an aside, and should be marked as nav. A site-wide footer-like block in a sidebar is not automatically tangential content either. Another mistake is to use aside as a generic styling hook for any boxed content, which dilutes its meaning in the same way div soup dilutes all semantics. Reserve aside for genuinely tangential material, apply the removal test before using it, and your sidebars will be both visually distinct and structurally honest. A pull quote marked as an aside inside an article is understood as related to that article, whereas the same content placed outside the article would be read as related to the whole page.
Check: What test tells you something belongs in an aside?
Section 19 — The footer element
The <footer> element marks closing content for a page or for a section: the material that rounds off what came before it rather than introducing something new. At page level, a footer typically contains copyright information, contact details, links to privacy and terms pages, a sitemap, and credits. At section or article level, a footer contains closing material for that piece: author information, publication date, related links, or a note about licensing. Like header, footer is defined by its role — closing — not by its position at the bottom of the screen, although page footers do usually appear there.
Also like header, a page can have more than one footer. An article footer sits at the end of its article, giving that article's author and date, while the page footer sits at the end of the whole document, giving site-wide information. This multiplicity is a feature, not an error, because it lets each piece of content carry its own closing information without confusing it with the site's. A screen reader that encounters an article footer understands it as belonging to that article, not as the end of the entire page, provided the nesting reflects that relationship. Placing an article footer outside its article, or a page footer inside a single section, would break that association and mislead the reader.
What belongs in a footer follows from its closing role. Copyright notices, authorship and contact information, links to related documents, and back-to-top links are all natural footer content. What does not belong there is primary content that a visitor came for, or navigation that is the main way around the site — that belongs in main or nav respectively, even if it also appears near the bottom of the page. A footer that contains the article itself, or the only navigation on the page, is misusing the element as a positional container rather than a semantic one. The test, as with header, is role: does this content close or support the preceding content, or is it the content itself?
Footers are also where legal and practical information most naturally lives, and that has a usability benefit: visitors have learned to look at the bottom of a page for copyright, contact and policy links, so placing them in a real footer element aligns the structure with visitor expectations and with search engines' understanding of the page. Keep footers concise and relevant to their scope — a page footer should not repeat every article's metadata, and an article footer should not carry site-wide policy links that belong to the page footer. That discipline keeps each footer useful and prevents the bottom of the page from becoming a dumping ground for anything that did not fit elsewhere. An article footer that lists its tags or categories can also help visitors discover related content, without turning those links into the page's main navigation.
Check: What kind of information belongs in a footer?
Section 20 — Divs and spans
The <div> and <span> elements are the generic containers of HTML: div for block-level grouping and span for inline grouping, with no meaning of their own. They exist for the cases where no semantic element fits — for example, wrapping several elements so a layout can position them together, or wrapping a few words inside a sentence so a style or a script can target them. In those cases, div and span are not a failure of semantics; they are the honest admission that the grouping has no semantic meaning beyond "these things go together for presentation or scripting". Used that way, they are essential tools.
The problem arises when div and span are used as substitutes for semantic elements that do fit. A page built entirely from divs — often called "div soup" — may look perfect, but it tells a screen reader nothing about which block is navigation, which is the main content, and which is a footer. A span used for a heading, a button, or a link is worse, because it not only hides meaning but also loses the built-in behaviour of the real element: a real button can be activated by keyboard and announced as a button, while a span styled to look like a button cannot, unless extra code is added to imitate it. The rule is therefore to reach for the semantic element first, and to fall back to div or span only when you have checked and found that none fits.
There are legitimate uses that illustrate the boundary well. A div wrapping a set of cards purely to create a grid layout is reasonable if the cards themselves are marked as articles or sections; the div adds layout, not meaning, and that is its job. A span wrapping a price inside a sentence so it can be styled differently is reasonable, because the price is part of the sentence's meaning, not a separate semantic unit. A div wrapping an entire page's header content instead of a header element is not reasonable, because header fits exactly. The question to ask is always: "Is there an element that already means this?" If the answer is yes, use it; if the answer is genuinely no, div or span is correct.
Beginners sometimes feel guilty about using div at all, as if every div were a failure. That guilt is misplaced. Semantic HTML does not mean eliminating divs; it means eliminating meaningless divs where a meaningful element exists. A well-structured page will still contain divs for layout wrappers and spans for small inline hooks, and that is fine. What distinguishes a good page from div soup is not the absence of divs, but the presence of semantic landmarks around them, so that the generic containers are the exception — used for presentation — rather than the whole structure.
Check: When is a div the right choice?
Section 21 — Why semantic HTML beats div soup
Div soup is a page built almost entirely from divs and spans, with class names doing all the work of describing the structure. Visually, such a page can be indistinguishable from a semantic one: the same layout, the same colours, the same text. The difference appears the moment anything other than eyes reads the page. A screen reader navigating div soup finds no landmarks to jump to, no headings that are actually headings, no navigation block it can skip, and no main region it can jump straight to. It must read through everything in order, or rely on class names that it cannot interpret. A semantic page, by contrast, offers its shape for free: header, nav, main, article and footer are landmarks that assistive technology understands without any extra code.
Search engines benefit in a similar way. They do not see the page as a human does; they parse its structure to decide what it is about, which parts are central and which are repeated furniture. A heading inside a semantic structure carries more weight as a topic label than the same words inside a div, because the structure confirms that the words are a heading, not merely large text. A page whose main content is marked as main is easier to summarise than a page where the main content is one div among many identical divs. Semantic HTML does not guarantee a ranking, and no honest teacher should claim it does, but it removes ambiguity about what the page means, and that clarity helps every automated reader that processes it.
Semantic HTML also helps the humans who maintain the page. A future developer opening a semantic file can see at a glance where the navigation lives, where the article begins, and where the footer starts, without decoding a system of class names that may be inconsistent or undocumented. That readability makes changes safer: moving an article, restyling a sidebar, or adding a new section is less likely to break something else when the boundaries are marked by elements rather than by convention alone. Class names can be changed, misspelled or forgotten; element names carry their meaning with them and are checked by validators. In a team, that shared vocabulary is worth more than any clever class system.
The objection sometimes raised is that semantic elements restrict design, or that a div is more flexible. In practice, semantic elements accept the same CSS as divs: you can style a header, a nav or an article in any way you can style a div, because CSS does not care about the tag name except as a selector. There is therefore no visual cost to using semantics, only a gain in meaning. The habit to form is to ask, for each block, "What is this?" before asking "How should it look?" If the answer is a header, a nav, a main, an article, an aside or a footer, use that element and style it as you wish. Div soup is not a style choice; it is a page that has chosen to say nothing about itself.
Check: What does a screen reader gain from semantic elements?
Section 22 — Heading order as an outline
Headings form the outline of a document, in the same way chapter and section titles form the outline of a book. A well-ordered page has one h1 that names the whole page, h2 elements that name its major parts, h3 elements that name subparts under those h2s, and so on, without skipping levels. Skipping a level — jumping from an h2 straight to an h4, for example — is like numbering book sections 1, then 1.2.1, with no 1.1 or 1.2 in between: the reader can still guess what was meant, but the structure is broken and the outline no longer reflects a clean hierarchy. Screen readers in particular rely on that hierarchy, because they let visitors navigate by heading level and build a table of contents from the headings alone.
The test for a good heading order is to extract the headings, in order, and read them without the body text. If they read like a sensible table of contents — each heading clearly belonging under the one above it, with no orphaned subheadings and no sudden jumps — the order is right. If the list reads like a random set of phrases, or if a heading only makes sense when you have already read the paragraph before it, the headings are probably being used for visual size rather than for structure. That is the most common heading mistake: choosing an h3 because it looks the right size, rather than because it is a subheading of the preceding h2. Size is a CSS decision; level is a structural decision, and the two should never be confused.
A single h1 per page is the usual rule, and it follows from the outline idea: a document has one overall title, and everything else is a part of it. There are technical exceptions in complex documents, but for the pages you will build in this book, one h1 is the safe and clear choice. That h1 should name the page's job, matching the title element in spirit if not in exact words, so that a visitor who lands on the page immediately knows what it is about. Subsequent headings should then break that job into parts, and subheadings should break those parts into smaller steps, each level adding detail without changing topic abruptly.
Fixing a broken outline is usually straightforward once you can see it. List the headings, identify where a level has been skipped or where a heading sits at the wrong level for its topic, and adjust the level — not the wording — to fit the hierarchy. If a section genuinely needs a subheading but its parent level is missing, add the missing parent heading or promote the subheading to the correct level, rather than leaving a gap. If two headings at the same level actually describe topics at different depths, demote one. The goal is not to satisfy a validator for its own sake, but to give every visitor, including those who navigate by headings alone, a reliable map of the page.
Check: Is it acceptable to jump from an h2 straight to an h4?
Section 23 — Paragraphs, revisited
A paragraph in HTML is one idea, expressed in one <p> element, regardless of how many lines it occupies on screen or in your source file. Browsers collapse sequences of spaces, tabs and line breaks inside a paragraph into single spaces when rendering, so pressing Enter in your source, or even pressing it twice, does not create a new paragraph. Only a new <p> element does. That behaviour surprises beginners who expect HTML source to behave like a word processor, where a blank line starts a new paragraph, but it is deliberate: HTML separates content from presentation, and whitespace in source is treated as formatting for humans, not as instructions for browsers.
That collapsing rule has practical consequences for how you write. You can break a long paragraph across several source lines for readability without affecting the rendered output, and you can indent it freely, because the browser will reflow it according to the width available. Conversely, if you want a visible line break inside a paragraph without starting a new idea — for example, in an address or a poem — you need the <br> element, which is a deliberate line break, not whitespace. Using <br> repeatedly to simulate paragraphs is a common mistake: it creates visual gaps without creating separate ideas, so screen readers and search engines still see one long paragraph, and styling paragraphs as units becomes impossible. Separate ideas deserve separate <p> elements.
Good paragraphing is also a writing skill, not just a markup skill. Each paragraph should contain one main idea, with supporting sentences that develop it, and the next paragraph should move to the next idea. A paragraph that runs for twenty lines on screen is hard to scan, hard to read on a phone, and hard to restyle, even if it is technically valid. Breaking it into two or three focused paragraphs improves readability for everyone and gives your CSS sensible units to space and style. Readers scan pages by paragraph breaks as much as by headings, so paragraphing is part of structure, not just a typing habit.
Finally, remember what a paragraph cannot contain. A <p> element is for phrasing content — text, links, emphasis, images — not for block elements such as headings, lists, or other paragraphs. If you place a block inside a paragraph, the browser will close the paragraph early, and the block will become a sibling rather than a child, which can break both styling and the outline. When you need a block inside a paragraph-like flow, restructure: close the paragraph, place the block, and open a new paragraph afterwards. That discipline keeps the document tree exactly as you intended, and it reinforces the central lesson of this chapter: in HTML, meaning comes from elements, not from how the source looks on your screen. Short paragraphs also help on small screens, where a long block of text can fill several screens and make it hard for a reader to keep their place.
Check: Why doesn't pressing Enter twice in HTML source make two paragraphs?
Section 24 — Quotations
Quotations in HTML come in two forms, distinguished by length and by how they sit in the text. A short quotation inside a sentence — a phrase or a sentence quoted as part of your own sentence — uses the <q> element, and browsers typically render it with quotation marks added automatically. A longer quotation that stands alone as a block, such as a paragraph quoted from another article, a speech, or a report, uses the <blockquote> element, which browsers typically render indented and separated from the surrounding text. Choosing between them is a question of role: is the quotation embedded in your sentence, or does it stand apart as a block of someone else's words?
Both elements can carry a cite attribute containing the URL of the source, which is useful for machines and for readers who want to verify the quotation, even though browsers do not usually display that URL visually. For a visible attribution, you can add a citation inside or after the block, naming the author and the work, often with a link to the source. The <cite> element itself is for the title of a work — a book, an article, a film — not for the name of a person, a distinction that beginners often miss. A correct pattern is therefore a blockquote with a cite attribute for the source URL, followed by a footer or paragraph naming the author and citing the work's title, so that both human and machine readers can trace the quotation.
Quotation marks themselves need care. Because browsers add marks around <q> content automatically, you should not type your own quotation marks inside a q element, or the result will show doubled marks. For blockquotes, by contrast, browsers do not add marks, so the quoted text stands without them unless you add them deliberately for style. Another common error is using blockquote purely to indent text that is not a quotation at all. That was a habit from early web design, when blockquote was misused as an indentation tool, but it misdescribes the content: a screen reader may announce indented non-quotations as quotations, confusing the listener. If you only want indentation, use CSS.
Quotations also raise a question of accuracy that markup alone cannot solve. Quoting accurately means preserving the original wording, not paraphrasing inside quotation marks, and making clear where a quotation begins and ends. Ellipses and bracketed clarifications belong to editorial practice, not to HTML, but the element choice supports that practice by making the boundary explicit in the code. When a quotation is marked correctly, a reader — human or machine — can tell at a glance which words are yours and which are someone else's, and can follow the citation to check them. That transparency is the point of having quotation elements at all, beyond mere styling. If you shorten a quotation with an ellipsis, make sure the remaining words still fairly represent the original, because accurate attribution is a matter of honesty as well as markup.
Check: Which element is for a long, stand-alone quotation?
Section 25 — Code in HTML
Displaying code inside a web page requires two elements working together, because code has two needs: it must be marked as code, and its whitespace must be preserved. The <code> element marks a fragment of code inside text — a function name, a variable, a short command — and browsers typically render it in a monospace font to distinguish it from ordinary prose. The <pre> element preserves whitespace and line breaks exactly as written, so indentation and line structure survive rendering instead of being collapsed as they are in a normal paragraph. For a multi-line code block, the standard pattern is therefore <pre><code>...</code></pre>: pre preserves the shape, code marks the meaning, and together they produce a readable block.
The most important technical detail is escaping. Inside a code sample, the characters < and > cannot be written literally, because the browser will interpret them as the start or end of a tag. To show them as text, you must write them as entities: < for < and > for >, and & for an ampersand. A sample showing <p>Hello</p> must therefore be written as <p>Hello</p> in the source. If you forget to escape, the browser will try to parse your sample as real HTML, the sample will vanish or render as actual elements, and the page's structure may break. Many editors and code-highlighting tools escape automatically, but when you write by hand, escaping is your responsibility and the first thing to check when a sample looks wrong.
There is also a distinction between inline code and code blocks that beginners sometimes blur. Inline code, using code alone inside a paragraph, is for short fragments that are part of a sentence: "Use the <title> element for the page name." A block, using pre and code together, is for listings that need their own lines and indentation: a function, a stylesheet rule, or a complete document skeleton. Using a block for a single word wastes space and breaks the sentence flow; using inline code for a multi-line listing collapses its line breaks and destroys its readability. Choosing the right form follows the same principle as the rest of this chapter: the markup should reflect the role of the content.
Finally, keep code samples short, correct and focused. A sample should demonstrate exactly the point being taught, with no unrelated lines that distract or confuse, and it should actually work if a reader copies it. Long, untested samples that contain errors teach the wrong lesson twice over: the reader learns the wrong code and loses trust in the material. Test every sample by rendering it, check that escaped characters display correctly, and trim anything that does not serve the example. A short, accurate sample that a reader can understand at a glance is worth far more than a long listing that impresses but does not teach. Some editors add a language class to the code element, such as language-html, which later chapters can use for syntax highlighting without changing the underlying meaning.
Check: Why must angle brackets be escaped inside a code sample?
Section 26 — Entities
An entity is a short code, beginning with an ampersand and ending with a semicolon, that represents a character which is hard to type, hard to display, or has a special meaning in HTML. The best-known examples are & for an ampersand, < for a less-than sign, > for a greater-than sign, " for a quotation mark, and © for the copyright symbol. Entities exist because HTML uses some characters for its own syntax: a literal < in text would be read as the start of a tag, and a literal & would be read as the start of an entity. Writing the entity instead tells the browser, unambiguously, "show this character as text".
In modern practice with UTF-8, you do not need an entity for every special character. Accented letters, currency symbols, and characters from other scripts can be typed directly into a UTF-8 document and will display correctly, provided the file is saved as UTF-8 and the charset is declared. Entities remain essential, however, for the characters that HTML reserves: the ampersand, the less-than and greater-than signs, and quotation marks inside attribute values delimited by the same kind of quote. A common beginner error is writing a bare ampersand in text such as "Fish & Chips" without realising that the browser will try to interpret what follows as an entity name; in most cases it will still display, but it is invalid and can break if the following text happens to look like an entity. Writing & is always safe.
Entities can be written by name, as in the examples above, or by number, using the character's code point, such as © for the copyright symbol. Named entities are easier to read and remember for common characters, while numeric entities are useful for characters without a convenient name. Both forms require the trailing semicolon; omitting it is a frequent source of errors, because the browser may then treat the following text as part of the entity and display the wrong character or nothing at all. A validator will flag missing semicolons, so checking your entities when a symbol displays incorrectly is a quick diagnostic step.
A useful habit is to think of entities as an escape hatch, not as a default way of writing text. Type ordinary characters directly, use entities only where HTML syntax or display requires them, and be especially careful inside code samples and attribute values, where a single unescaped character can change the parsing of everything that follows. That restraint keeps source readable: a paragraph full of numeric entities for ordinary letters is hard to edit and hard to proofread, while a paragraph that uses entities only for its reserved characters reads almost like the final text. Entities are a small tool, but using them precisely is part of writing HTML that means exactly what it says. When you copy text from another source into HTML, check for stray ampersands in company names or phrases, because those are the characters most likely to be left unescaped by accident.
Check: Write the entity for an ampersand.
Section 27 — Strong versus bold
The elements <strong> and <b> both typically render as bold text, which tempts beginners to treat them as interchangeable. They are not. Strong means the text is important: it carries extra weight in the sentence, and a screen reader may stress it or announce it differently to convey that importance. Bold, by contrast, means only that the text should look bold, with no added importance or emphasis in meaning. The visual result may be identical in a default browser, but the meaning communicated to non-visual readers is different, and that difference is the whole point of having two elements.
Choosing between them is therefore a question of intent, not appearance. If you are marking a warning, a crucial instruction, or a key term whose importance the reader must grasp — "Do not delete this file" — strong is correct, because the importance is part of the message. If you are marking text bold purely for a visual convention, such as a product name in a list, a keyword in a summary, or a lead-in word that is bold by house style without being more important than its neighbours, b is the honest choice. Using strong for every bold word dilutes its meaning: if everything is important, nothing is, and a screen reader user who hears every other phrase stressed will quickly learn to ignore the stress altogether.
The same meaning-first principle applies in reverse. If you want text to look bold but you use strong to achieve it, you are lying about importance for the sake of appearance, and you are also making future styling harder: a stylesheet that restyles strong elements globally will affect all your fake-importance text as well. The correct workflow is to choose the element for its meaning, then use CSS to adjust appearance if the default bold rendering does not suit your design. If strong text should not look bold in a particular design, CSS can remove the boldness while preserving the importance; if b text should look bold, CSS already gives you that by default. Meaning and appearance are separate jobs, and HTML handles the first.
In practice, strong is the element you will use more often, because most of the time when a writer bolds text, they do mean it to stand out as important. Bold remains useful for the smaller set of cases where boldness is a typographic convention without semantic weight. Keeping that distinction clear — importance versus appearance — will also prepare you for the parallel distinction between emphasis and italics in the next section, where the same rule applies. Both pairs teach the same lesson: in semantic HTML, you mark what content means first, and you let the browser and CSS decide how that meaning is presented. In a set of instructions, marking the safety warning as strong rather than merely bold ensures that a listener hears its importance even if they cannot see its formatting.
Check: Which element tells a screen reader the text matters?
Section 28 — Emphasis versus italics
The elements <em> and <i> both typically render as italic text, but they differ in meaning in exactly the same way strong differs from bold. Emphasis means that stressing the word changes the meaning of the sentence: "I said the report was due on Friday, not Thursday" emphasises Friday to correct a misunderstanding, and a screen reader may convey that stress vocally. Italics, by contrast, means only that the text should look italic, for a typographic convention such as a foreign phrase, a scientific name, a ship's name, or a term being defined. The visual similarity hides a semantic difference that matters to anyone who does not read the page visually.
The test for em is to ask whether stressing the word aloud would change what the sentence communicates. If you read "She did not say that" with stress on "did", you are denying that she said it; with stress on "that", you are denying the content. That shift in meaning is what em marks. If no such shift exists — if the italic text is a book title, a Latin phrase, or a technical term introduced for the first time — then i is more accurate, because the italics are a publishing convention, not a change in spoken emphasis. Using em for a book title would tell a screen reader to stress the title as if correcting someone, which is misleading even though the visual result looks right.
As with strong and bold, the mistake to avoid is choosing by appearance. Beginners often pick em because they want italics, without considering whether emphasis is meant, and then every italic phrase on the page is announced with vocal stress, diluting the effect for the phrases where stress genuinely matters. The remedy is the same: choose the element for its meaning, and let CSS handle appearance. If you need italic text that is neither emphasis nor a conventional italic case, CSS font-style can produce italics without claiming a meaning that is not there. That option is a reminder that HTML elements are not styling tools; they are meaning tools, and CSS exists precisely so that meaning and presentation can be decided independently.
Taken together, the strong/bold and em/i pairs form a compact lesson in semantic thinking. In each pair, one element carries meaning that assistive technology can convey, and the other carries only a visual convention. Learning to pause and ask "Do I mean importance, emphasis, or just a look?" before choosing may feel slow at first, but it quickly becomes automatic, and it produces pages whose meaning survives translation to speech, to search indexes, and to any future design. That durability is why semantic distinctions that seem pedantic on screen are worth mastering early. Nesting emphasis inside strong, or the reverse, is valid when both meanings apply, but use that combination sparingly so that neither signal loses its force.
Check: When is i the right element instead of em?
Section 29 — Links, revisited: relative paths
A relative path is a link or resource reference that is interpreted from the location of the current file, rather than from the site root or from a full web address. If your page sits in the site root and links to images/logo.png, the browser looks for an images folder next to that page. If your page sits inside a pages/ folder and uses the same path, the browser looks for an images folder inside pages/, which usually does not exist, and the link breaks. To reach the root-level images folder from inside pages/, you must step up one level first with ../images/logo.png, where ../ means "go to the parent folder". Each additional ../ steps up one more level, so a page two folders deep needs ../../ to reach the root.
Understanding this rule requires a clear mental model of your folder structure. Draw it, or list it, before you start linking: root contains index.html, a css folder, an images folder, and a pages folder containing about.html and contact.html. From index.html, the path to the logo is images/logo.png. From pages/about.html, the path is ../images/logo.png. From pages/contact.html to pages/about.html, the path is simply about.html, because both files share the same folder. From pages/about.html to the stylesheet, the path is ../css/style.css. Working through those examples slowly, on paper if needed, builds the intuition that makes relative paths feel natural instead of mysterious.
Relative paths have advantages that explain why they are the default for internal links. They keep a site portable: if you move the whole site folder to a different domain or to a subfolder, internal relative links still work, because they describe relationships between files rather than absolute locations. They also make local development easier, because a site previewed from a local folder behaves the same way it will when published, provided the folder structure is preserved. Absolute paths beginning with a slash, by contrast, describe locations from the domain root, which can break when a site is served from a subfolder, and full URLs are unnecessary for internal links and harder to maintain if the domain changes.
The most common relative-path errors are counting levels incorrectly, forgetting that the path is relative to the HTML file rather than to the CSS file or the site root, and mixing path styles inconsistently within a project. A stylesheet's internal references, such as background images, are relative to the stylesheet's location, not to the page that loads it — a subtlety that catches many beginners when an image loads on one page but not on another. When a link or image fails, the browser's developer tools will show the exact path it tried, and comparing that path with your folder structure usually reveals whether you need one more ../, one fewer, or a different starting folder. That diagnostic habit turns path errors from frustrations into quick fixes. A root-relative path beginning with a slash can be useful on a large site, but test it when the site is served from a subfolder, because the domain root may not be the site root.
Check: From inside pages/about.html, how do you link to images/logo.png in the root?
Section 30 — Anchor links within a page
An anchor link within a page lets a visitor jump to a specific part of the same document without reloading it and without any JavaScript. The mechanism has two parts: a target element with a unique id attribute, such as <h2 id="pricing">Pricing</h2>, and a link whose href begins with a hash followed by that id, such as <a href="#pricing">See pricing</a>. When the visitor activates the link, the browser scrolls to the element with the matching id and updates the address bar to include the fragment, so the link can also be shared or bookmarked to land directly on that section. The hash in the href is therefore not decoration; it signals "look inside this document for an element with this id".
Tables of contents are the most familiar use of anchor links. A long tutorial or documentation page can list its sections at the top, each linking to the corresponding heading below, so a visitor can jump straight to the part they need instead of scrolling through everything. "Back to top" links work the same way in reverse, linking to an id on the page's top element or to #top if such an id exists. Footnotes, FAQ answers, and step-by-step guides all benefit from the same pattern, because it turns a long page into a navigable document without adding any scripting complexity. For accessibility, anchor links are especially valuable: a screen reader user can move through a long page by its headings or by its table of contents, rather than reading linearly from the start.
For anchor links to work, ids must be unique within the page and must be written correctly. Duplicate ids are a common error, especially when a template is copied: the browser will jump to the first matching element, which may not be the one the link intended, and a validator will flag the duplication. Id values should also be simple and predictable — lowercase letters, numbers, hyphens and underscores, with no spaces — so that the href fragment matches exactly. A mismatch as small as a capital letter or a missing hyphen breaks the link silently: the browser does nothing, or jumps to the top, and the visitor is left wondering why the link failed. Checking ids and fragments together, preferably by clicking each table-of-contents link after writing it, catches those mismatches early.
It is also worth understanding what anchor links do not do. They do not create new pages, they do not require JavaScript, and they do not by themselves add smooth scrolling or highlighting — those are enhancements that CSS or JavaScript can add later. Their core value is structural: they expose the document's internal landmarks as linkable destinations. When you give every major heading a stable id and link to those ids from a table of contents, you are treating a long page as a small site of its own, with its own navigation. That habit makes long content far more usable, and it costs nothing beyond the discipline of adding ids consistently.
Check: What does the # in a href mean?
Section 31 — Email and telephone links
Email and telephone links turn contact information into actions, using special URL schemes in the href instead of a web address. An email link uses the mailto: scheme, as in <a href="mailto:hello@example.com">Email us</a>, and activating it opens the visitor's default email program with a new message addressed to that address. A telephone link uses the tel: scheme, as in <a href="tel:+2348000000000">Call us</a>, and activating it on a phone starts a call to that number, while on a desktop it may offer to call through an installed application or do nothing if no calling app is configured. Both are ordinary links in markup; only the scheme changes what the device does with them.
The telephone number in a tel link should be written in international format, beginning with a plus sign and the country code, without spaces, brackets or hyphens that a dialler might misinterpret. For a Nigerian number, that means +234 followed by the number without its leading zero, rather than a local format that only works inside Nigeria. The visible link text, by contrast, can be written in a human-friendly format with spaces, because visitors read the text, not the href. That separation — machine-readable href, human-readable text — is the same principle as the time element in Section 35: the attribute carries the precise value, while the visible text carries the friendly version.
Email links can also include a prefilled subject or body, using a query string after the address, such as mailto:hello@example.com?subject=Question%20about%20pricing. Spaces and special characters in that query must be percent-encoded, or the link may break or produce a garbled subject line. Use that feature sparingly: a prefilled subject can help a visitor who does not know what to write, but a long prefilled body that the visitor did not write feels presumptuous and may be edited or abandoned. A simple address link, with clear link text saying what the email is for, is usually the most respectful and reliable choice.
There is a trade-off to understand before publishing an email address as a mailto link. Any address visible in page source can be harvested by spam bots that crawl the web collecting addresses, so a public mailto link will almost certainly attract spam over time. That does not mean you should never use one — for a business contact page, the benefit of easy contact often outweighs the spam cost, especially if spam filtering is in place — but it does mean you should not publish a personal address casually, and you should consider a contact form as an alternative when spam is a serious concern. A form keeps the address hidden while still letting visitors contact you, at the cost of extra development. Weighing that trade-off, rather than adding mailto links by default, is part of professional judgement. For a phone number shown on a desktop page, consider also showing the number as readable text, so visitors without a calling app can still copy it manually.
Check: Which href scheme starts a phone call on a mobile device?
Section 32 — Opening links in a new tab
The target="_blank" attribute on a link tells the browser to open the linked document in a new tab or window instead of replacing the current page. That can be appropriate when the visitor is in the middle of a task they should not lose — for example, reading a form's help page, checking a reference while filling in an application, or following a citation from an article they intend to return to. In those cases, a new tab preserves the visitor's place and lets them return easily. Used as a default for every external link, however, it becomes an annoyance: tabs multiply, the back button stops working as expected, and visitors who use screen readers or mobile browsers may lose track of where they are.
The deeper reason to use new tabs sparingly is control. Opening a link in the same tab is the web's default, and visitors know how to open a new tab themselves — by right-clicking, long-pressing, or using a keyboard shortcut — when they want one. Forcing a new tab takes that choice away and assumes you know better than the visitor how they want to browse. That assumption is sometimes justified, as in the help-page example, but it should be a deliberate decision with a reason, not a habit applied to every link because it feels safer to keep visitors on your site. A visitor who wants to stay will use the back button or open the link in a new tab themselves; a visitor who is forced into new tabs may simply close them all.
When you do use target="_blank", you must pair it with rel="noopener", as in <a href="https://example.com" target="_blank" rel="noopener">. Without noopener, the newly opened page receives a reference to the original page through the window.opener object, and a malicious or compromised page could use that reference to redirect the original page to a phishing site — a technique sometimes called tabnabbing — while the visitor is distracted by the new tab. The noopener value severs that connection, so the new page cannot reach back into yours. Many modern browsers now imply noopener by default for _blank links, but relying on that default is unwise: explicit rel="noopener" is clear, backwards-compatible, and communicates your intent to anyone reading the code.
A related value, noreferrer, also prevents the new page from receiving the referrer information about where the visitor came from, and it implies noopener in many browsers. You may see rel="noopener noreferrer" used together, and that combination is common and safe. What matters most is that _blank never appears alone in your code. Check for it whenever you review links, add noopener as a matter of routine, and ask for each new-tab link whether the visitor's task genuinely benefits from a new tab. If the answer is no, let the link behave normally and trust the visitor to manage their own tabs. Warn visitors when a link opens a new tab only if it genuinely affects their task, for example by adding the words opens in new tab to the link text, rather than surprising them.
Check: Why pair target="_blank" with rel="noopener"?
Section 33 — Images, revisited: srcset basics
A single fixed-size image is a compromise that pleases nobody on a web of many screen sizes. A large image that looks sharp on a desktop monitor wastes bandwidth on a small phone, where it must be downloaded in full and then shrunk to fit. A small image that loads quickly on a phone looks blurry when stretched across a large screen. The srcset attribute solves this by letting you offer the same image at several sizes and letting the browser choose the version that best fits the device, the screen density, and the layout width. The browser, not the author, makes the final choice, because only the browser knows the screen it is running on and the network conditions it faces.
In its simplest form, srcset lists image files with width descriptors, such as srcset="photo-400.jpg 400w, photo-800.jpg 800w, photo-1200.jpg 1200w", alongside a sizes attribute that tells the browser how wide the image will be displayed at different viewport widths. The browser then compares the displayed size with the available files and picks the smallest file that will still look sharp, avoiding both waste and blurriness. There is also a density form, using descriptors like 1x and 2x, for cases where the same displayed size needs a higher-resolution file on a high-density screen. The width form is the more flexible of the two for responsive layouts, and it is the one you will use most often, with full detail reserved for the responsive chapter.
The ordinary src attribute remains alongside srcset, and it should not be removed. It serves as the fallback for browsers that do not understand srcset, and it provides the default image if srcset parsing fails. A common beginner error is to replace src with srcset entirely, leaving older browsers with nothing to display. Another error is to offer several sizes that are actually the same file renamed, or to offer sizes that do not match the layout: if your image is never displayed wider than 600 pixels, offering a 2400-pixel version wastes the effort of creating it, and if your sizes attribute lies about the displayed width, the browser will choose poorly despite having good files. Accuracy in sizes is therefore as important as having multiple files.
Preparing srcset images is also a workflow lesson. You need to export the same image at each size, with consistent cropping and compression, and to name the files clearly so the relationship between them is obvious. That work pays off in performance: a phone on a slow connection downloads a small file quickly, a desktop on a fast connection downloads a sharp file, and neither visitor pays for the other's needs. For this chapter, the takeaway is conceptual rather than complete mastery: know that one fixed image is not always enough, know that srcset exists to offer alternatives, and know that the browser chooses among them based on the information you give it. The responsive chapter will turn that understanding into a working technique.
Check: What problem does srcset solve?
Section 34 — Figures and captions
A <figure> groups a piece of self-contained content — most often an image, but also a diagram, a chart, a code listing, or an audio clip — together with its caption, so that the content and its explanation travel as a unit. The caption is marked with <figcaption>, and it must be either the first or the last child of the figure element. That placement rule is what binds caption to figure in the document structure: a screen reader can announce the caption as belonging to the figure, a search engine can associate the explanatory text with the image, and a developer moving the figure to another part of the page moves its explanation with it automatically, instead of leaving an orphaned paragraph behind.
The caption itself should explain, not merely label. A caption that repeats the image's alt text adds little, because alt text already describes the image for those who cannot see it. A good caption adds context: what the image shows that is not obvious, why it matters to the surrounding text, what the reader should notice, or where the image came from. For a chart, the caption might state the conclusion the chart supports; for a photograph, it might give the location and date; for a code listing, it might summarise what the code demonstrates. That explanatory role is why figure and figcaption exist as a pair: the figure is the evidence, and the caption is the interpretation that makes the evidence useful.
A common mistake is to use figure for every image, including purely decorative images or images that are already fully explained by the surrounding paragraph. If an image is decorative, it needs no caption and no figure; if its explanation is already in the main text, wrapping it in a figure with a redundant caption adds structure without adding meaning. Conversely, an image that does carry independent information — a diagram whose labels matter, a photograph that is itself the subject of discussion — deserves a figure, because its caption is part of the content, not a decoration. The test is whether the image plus its caption form a unit that could be referenced from elsewhere in the text, as in "see Figure 1", and still make sense. If it could, figure fits; if not, a plain image with alt text is enough.
Figures can also contain more than one image, or a mix of media, provided they form a single unit with a single caption. A before-and-after pair, for example, can sit inside one figure with a caption explaining the comparison, which is clearer than two separate images with separate captions that a reader must connect themselves. Keep the figure's content focused, however: a figure that contains an entire section's worth of unrelated images is not a unit, and its caption cannot honestly explain all of them. Used with that discipline, figure and figcaption turn images from floating decorations into referenced, explained parts of the document.
Check: Where does a figcaption sit in relation to its figure?
Section 35 — The time element
The <time> element solves a mismatch between how humans write dates and how machines read them. Humans write "29 October 2026", "next Friday", or "3pm", in forms that vary by language, culture and context. Machines — search engines, calendars, screen readers, and data tools — need a precise, unambiguous value to work with. The time element carries both: its visible text shows the friendly version to visitors, while its datetime attribute holds the machine-readable version, such as <time datetime="2026-10-29">29 October 2026</time>. A visitor sees the words; a machine reads the attribute, and neither has to compromise for the other.
The datetime value follows a standard format, and getting that format right is essential. Dates use year-month-day order, as in 2026-10-29, times use twenty-four-hour format, as in 15:30, and combined date-times join them with a T, as in 2026-10-29T15:30. Durations and other forms have their own patterns, but for most pages you will need only dates, times, and combined values. A datetime that is misformatted — for example, written in day-month-year order, or with a month name instead of a number — will simply not be recognised as a date by machines, silently losing the benefit of the element. The validator and a quick check against the standard format will catch those errors, and it is worth checking every datetime you write until the format feels natural.
The practical benefits of time are easy to underestimate because they are invisible on the page. A search engine that can read a publication date can show it in results and help visitors judge whether an article is current. A calendar tool can offer to add an event date to a visitor's calendar. A screen reader can announce a date unambiguously, rather than relying on the visitor to parse a written format that might be ambiguous — is 03/04 March 4th or April 3rd? The datetime attribute removes that ambiguity for machines, while the visible text can use whatever format your readers find most natural. That separation is the same principle as in email and telephone links: precise data for machines, friendly text for humans, in a single element.
Not every mention of a date needs a time element. A date mentioned in passing inside a story, where its machine-readable value adds no value, can remain plain text without harm. Reserve time for dates and times that function as data: publication dates, event dates, deadlines, opening hours, and times within a schedule. Over-marking every date dilutes the signal, while marking the functional ones makes the page's temporal information genuinely useful. When you do mark a date, make sure the visible text and the datetime attribute agree — a visible "29 October 2026" paired with a datetime of a different day is worse than no markup at all, because it actively misleads the machines that trust the attribute. For an event that spans a time zone, include the offset in the datetime value, such as plus one hour, so the machine-readable time is unambiguous across regions.
Check: Why give a time element both visible text and a datetime attribute?
Section 36 — Abbreviations
An abbreviation is a shortened form of a word or phrase, such as HTML for HyperText Markup Language, and the <abbr> element marks it while giving its full form in a title attribute, as in <abbr title="HyperText Markup Language">HTML</abbr>. Browsers typically show that full form as a tooltip when a visitor hovers over the abbreviation, and screen readers may announce the expansion, helping readers who do not already know what the letters stand for. That help is the point of the element: abbreviations save space for insiders but exclude outsiders, and abbr bridges that gap without forcing the writer to spell out the full form every time.
The title attribute on abbr is not a general tooltip mechanism; it is specifically the expansion of the abbreviation. That distinction matters, because beginners sometimes use title on abbr for unrelated notes or jokes, which confuses the readers who rely on it for the full form. The expansion should be the complete, correct form, written out in full, not another abbreviation or a vague description. For "CSS", the expansion is "Cascading Style Sheets"; for "W3C", it is "World Wide Web Consortium". Getting the expansion right requires the same care as getting a definition right, because a wrong expansion teaches the wrong thing to every reader who hovers.
Good practice also involves defining an abbreviation in prose the first time it appears, rather than relying solely on the tooltip. A first mention written as "HyperText Markup Language (HTML)" teaches the reader immediately, and subsequent uses can then be marked with abbr alone, safe in the knowledge that the reader has already met the full form. Relying only on hover tooltips excludes visitors on touch devices, who cannot hover, and visitors using screen readers in ways that may not announce the title. The abbr element is therefore a supplement to good writing, not a substitute for it: define first in text, then mark subsequent abbreviations so that any reader who missed the definition can still recover it.
There are limits to abbr's usefulness that are worth knowing. Very familiar abbreviations that your audience certainly knows — such as HTML itself on a front-end developer site — do not need marking on every occurrence, and over-marking familiar terms adds noise to the source without helping readers. Conversely, an abbreviation that is so obscure or so context-specific that its expansion alone does not explain it needs a fuller explanation in the text, not just a tooltip. The judgement is audience-based: mark abbreviations that a reasonable reader of this page might not know, define them in prose on first use, and leave the rest as plain text. That balance keeps pages readable for both newcomers and experts. For example, marking NASA on first use with its full form helps a reader who knows the letters but has never seen them expanded in this context.
Check: What does the title attribute do on an abbr element?
Section 37 — Address content
The <address> element marks contact information for the author or owner of the page or article it appears in — an email address, a postal address, a telephone number, or a link to a contact page. Its scope is specific: it is about who to contact about this content, not about any address that happens to be mentioned in the text. That distinction is the key to using address correctly, and it is the source of its most common misuse. A shop's location mentioned inside a news story about that shop is not the story author's contact information, so it does not belong in an address element, even though it is an address in the everyday sense of the word.
Placement determines whose contact information the address element describes. An address inside an article describes contact information for that article's author; an address in the page footer describes contact information for the page or site owner. That scoping rule means the same element can serve different purposes in different places, provided it is nested correctly. An address placed outside any article, in the page footer, is naturally read as site contact information, while an address inside a blog post's footer is read as the post author's contact information. Misplacing it — for example, putting the site's contact address inside a single article — would attribute the site's contact details to that article's author, which is a small but real misdescription.
The content inside address should be contact information, not arbitrary footer content. Copyright notices, navigation links, and general site information do not belong in address simply because they sit in the footer alongside it. A typical correct footer might contain a copyright paragraph, a navigation list, and then a separate address element containing the owner's email and postal address. Keeping those parts distinct preserves the meaning of each: the address element says "contact this person or organisation about this content", while the surrounding footer says "here is closing information about the page". Mixing them blurs that distinction and makes the contact information harder for tools to extract.
Beginners sometimes avoid address altogether because its name suggests it is only for postal addresses, or they use it for every street address they mention. Both reactions miss its actual role as a contact container. If a page has contact information for its author — and most real pages should, at least in the footer — marking it with address is a small, correct step that helps browsers, search engines and contact-extraction tools identify it reliably. If a page mentions addresses that are not contact information, leave those as plain text. That single rule — contact for the content's author, not any address in the text — resolves almost every address question you will meet. If an article has several authors, the address element can list contact details for the group, provided it remains clear that it is contact information for those authors.
Check: Is address the right element for a shop's location in a story about it?
Section 38 — Horizontal rules
The <hr> element marks a thematic break between paragraphs — a shift in topic, a change of scene, or a transition to a different part of the content — rather than a mere visual line. In a story, an hr might separate one scene from the next; in an article, it might separate the main argument from a concluding note or a change of subject. Its meaning is structural: it says "what follows belongs to a different theme from what came before", in a way that a paragraph break alone does not convey. Browsers typically render it as a horizontal line, but that rendering is a consequence of its meaning, not its purpose.
That distinction between meaning and appearance is what determines when hr is wrong. If you only want a visual divider — a line under a heading, a border between cards, a decorative rule in a layout — then hr is the wrong element, and CSS is the right tool. A CSS border or background can draw a line exactly where you want it, in any style, without claiming a thematic break that does not exist. Using hr for decoration misleads screen readers, which may announce a thematic break where the content has not actually changed theme, and it makes the document's structure lie about its own organisation. The test is simple: if you removed the line visually, would the content still need a break? If the answer is no, do not use hr.
When hr is used correctly, it should sit between paragraphs or other block content, not inside a paragraph, and it should not be used repeatedly to create spacing. Multiple hrs in a row, or an hr used to push content apart, are signs that spacing is being handled by markup instead of CSS, which is fragile and hard to maintain. A single hr at a genuine thematic transition, by contrast, is both meaningful and visually clear, and it can be styled with CSS if the default line does not suit the design. Styling an hr does not change its meaning; it only changes how the thematic break is presented, which is exactly the division of labour HTML and CSS are designed for.
In practice, hr is an element you will use sparingly, because most thematic transitions in a well-structured page are already marked by headings and sections. A new section with its own heading already signals a change of theme more clearly than an hr could, so hr is most useful in the middle of a continuous flow — within a story, an essay, or a long article — where a heading would be too strong a break but a paragraph break alone would be too weak. Recognising that middle ground, and reserving hr for it, keeps the element meaningful instead of turning it into a decorative line that happens to have a tag name.
Check: When is hr the wrong element?
Section 39 — Details and summary
The <details> and <summary> elements together create a native expandable section — a disclosure widget — with no JavaScript required. The pattern is <details><summary>More info</summary><p>Hidden until opened.</p></details>: the summary is the visible label that the visitor clicks or activates, and everything else inside details is hidden until the widget is opened, then revealed. Browsers provide the interaction, the keyboard support, and the open-and-closed states automatically, which makes details one of the simplest interactive patterns in HTML. It is ideal for FAQs, where each question is a summary and each answer is the hidden content, and for optional detail that most visitors do not need but some will want.
The summary element controls the widget: it is the first child of details, it is always visible, and activating it toggles the rest of the content. That role should be reflected in its text, which should be a clear label for what will be revealed — a question in an FAQ, or a short description such as "Shipping information" or "Technical notes". A vague summary like "Click here" tells the visitor nothing about what they will get, and defeats the purpose of a disclosure, which is to let visitors decide whether the hidden content is relevant before revealing it. The summary can contain phrasing content, including links or emphasis, but it should not contain block elements or another interactive element that would confuse activation.
Accessibility is a major advantage of the native details element over a custom JavaScript accordion. Because the behaviour is built into the browser, screen readers understand the expanded and collapsed states and announce them correctly, keyboard users can operate the widget with standard keys, and the content remains available even if JavaScript fails or is disabled. A custom accordion built from divs and scripts must reimplement all of that — states, announcements, keyboard handling, focus management — and custom implementations frequently get one of those wrong. Unless you need styling or behaviour that details cannot provide, the native element is the safer and simpler choice, and it embodies the progressive enhancement principle of Section 48.
There are limits to be aware of. Styling details consistently across browsers requires some care, because browsers render the disclosure marker differently, and animating the opening and closing smoothly is not straightforward with the native element alone. Content inside a closed details element is also not visible to a visitor who searches the page with find-in-page in some browsers, although it remains in the document and is indexed. Those limits do not outweigh the benefits for simple disclosures, but they are reasons to choose details for FAQs and optional notes, rather than for critical content that every visitor must see. Critical content should be visible by default; details is for content that is useful on demand. On a long FAQ page, leaving the most important answer open by default with the open attribute can help visitors who need that answer immediately, while keeping the rest collapsed.
Check: What does the summary element control in a details block?
Section 40 — Hidden content
The hidden attribute hides an element from rendering until it is removed, typically by JavaScript when some condition is met. Writing <p hidden>This is hidden.</p> means the paragraph will not be displayed, will not take up space, and — in principle — will not be presented to assistive technology either, because hidden is a semantic statement that the content is not currently relevant, not merely a visual style. That semantic character distinguishes hidden from purely visual hiding techniques, and it is why hidden is useful for content that should be revealed later by interaction, such as a form section that only applies when a particular option is chosen, or a message that appears after an action.
The distinction from CSS display: none is subtle but important, and it is often overstated in simplified explanations. In practice, both hidden and display: none remove an element from visual rendering, and modern screen readers generally respect both by not announcing the hidden content. The difference is one of intent and of default behaviour: hidden is an HTML attribute that declares the content irrelevant for now, and browsers apply a default style equivalent to display: none to it, while display: none is a CSS declaration that can be overridden, combined with other styles, and used for purely presentational hiding. If a stylesheet overrides the hidden attribute's default display, the content may become visible despite hidden being present, which is why the two should not be mixed carelessly. For content that is semantically irrelevant until revealed, hidden is the clearer signal; for content hidden only for layout reasons, CSS is the appropriate tool.
A related technique, visually hiding content while keeping it available to screen readers, is a different case again, and it requires a specific CSS pattern rather than hidden or display: none. That pattern is used for labels or instructions that sighted visitors do not need because the visual design already conveys them, but that screen reader users still need to hear. Beginners sometimes use hidden for that purpose, expecting screen readers to still announce the content, and are surprised when it is not announced. The rule is therefore: if content should be available to assistive technology, do not use hidden or display: none on it; use a visually-hidden CSS technique designed for that purpose, which later chapters cover in detail.
Choosing deliberately among these options is the lesson of this section. Ask first whether the content is currently relevant at all: if not, hidden is appropriate and JavaScript can remove it when it becomes relevant. Ask second whether the hiding is only visual: if so, CSS is appropriate, and you must consider what assistive technology should do. Ask third whether the content should remain available to screen readers despite being visually hidden: if so, neither hidden nor display: none is right. That three-way check prevents the common error of hiding content from the very people who need it most, simply because a hiding technique was chosen for its visual effect without considering its semantic effect.
Check: What is the difference between hidden and display: none for assistive technology?
Section 41 — Data attributes
Data attributes, written as data-*, let you store extra information on an element for JavaScript to use, without affecting how the element renders or what it means. The pattern is <button data-price="500">Buy</button>, where the attribute name after data- is your own descriptive name, and the value is a string that a script can read. In JavaScript, those values are available through the element's dataset property, so button.dataset.price returns "500" for the example above. That bridge between HTML and script is the entire purpose of data attributes: they let markup carry the small pieces of data that behaviour needs, in the place where that behaviour applies.
A sensible use on a product card illustrates the idea well. A card might display a product name, an image and a formatted price for humans, while carrying data-product-id, data-price and data-in-stock attributes for a script that adds the product to a basket, calculates a total, or disables the button when stock runs out. Keeping those values on the card itself means the script does not need to parse the visible text to extract a price — a fragile approach that breaks when formatting changes, for example when a currency symbol or a thousands separator is added. The data attribute separates the machine value from the human display, just as the time element separates datetime from visible text, and that separation makes both more reliable.
There are rules for naming data attributes that keep them valid and predictable. The name after data- must be lowercase, must not contain uppercase letters, and should use hyphens to separate words, as in data-product-id; in JavaScript, those hyphens are converted to camelCase, so data-product-id becomes dataset.productId. The value is always a string in HTML, even when it looks like a number, so a script that needs a number must convert it explicitly rather than assuming arithmetic will work. Those details are small, but getting them wrong — using uppercase in the attribute, or forgetting to convert a string to a number — produces bugs that look mysterious until the naming rule is remembered.
Data attributes are not a place to hide visible content from users, nor a substitute for proper elements and attributes. Information that a visitor should be able to see or that assistive technology should announce belongs in visible text or in a semantic attribute designed for it, not tucked into a data attribute that only scripts read. Similarly, data attributes should not be used to store large amounts of data, sensitive information, or content that belongs in a database or an API response; they are for small, element-specific values that a script needs immediately. Used within those limits, they are a clean, standard way to connect markup to behaviour without inventing non-standard attributes that validators would flag and other developers would not recognise. A script that reads a data attribute should also handle a missing or empty value gracefully, rather than assuming every element it finds will carry the attribute.
Check: Give a sensible use for a data attribute on a product card.
Section 42 — Validating your HTML
A validator is a tool that checks your document against the HTML standard and reports errors and warnings, and running one regularly is one of the highest-value habits a front-end developer can form. The standard tool is the W3C validator, available as a web service where you can paste code, upload a file, or enter a page address. It parses your document as a browser would, compares the resulting structure with the rules of HTML, and lists every place where the document breaks those rules, with line numbers and explanations. Fixing those reports early prevents a category of bugs that are otherwise hard to trace, because an invalid structure can render correctly in one browser and incorrectly in another.
The errors a validator commonly catches will be familiar from earlier sections, which is why this section comes near the end of the chapter. Unclosed tags are a frequent report: an element opened but never closed, leaving the rest of the document nested inside it by accident. Bad nesting is another: elements closed in the wrong order, or block elements placed inside paragraphs where they do not belong. Duplicate ids are a third common error, where the same id is used on two elements, breaking anchor links and scripts that expect uniqueness. Other reports include missing required attributes, such as an image without alt text, elements used in the wrong context, such as a list item outside a list, and stray characters that suggest a typo in a tag. Each report points to a specific line, so fixing it is usually a matter of correcting that line rather than redesigning the page.
Validation is not a guarantee that a page is good, and it is important to understand its limits. A page can be fully valid and still be poorly structured, with headings used for size, sections without headings, or div soup throughout, because validity checks syntax and context, not the wisdom of your semantic choices. Conversely, a page can have a minor validation warning about an experimental feature and still work perfectly. Validation is therefore a floor, not a ceiling: it ensures your HTML is well-formed and follows the standard, so that browsers, assistive technology and search engines all build the same tree from it. Good structure, accessibility and design are built on top of that floor, not replaced by it.
Make validation part of your workflow, not a final chore. Validate after building the skeleton of a page, again after adding major sections, and again before publishing, rather than waiting until a page is finished and facing a long list of errors at once. Fix errors in order, because one error — such as an unclosed element early in the document — can cause a cascade of later reports that disappear once the first is fixed. Treat warnings seriously but judge them: a warning about a missing heading in a section may indicate a real structural gap, while a warning about a vendor-specific attribute may be a deliberate choice. That judgement, applied regularly, turns validation from a test you pass into a tool you learn from.
Check: Name two errors a validator commonly catches.
Section 43 — Indentation as communication
Indentation — the spaces at the start of a line that show how deeply an element is nested — does not change how a browser renders a page. A document with no indentation at all will render identically to the same document indented beautifully, because browsers ignore leading whitespace between elements for layout purposes. Indentation's audience is therefore entirely human, and its value lies in making structure visible. When child elements are indented inside their parents, a reader can see the document's tree at a glance: which elements belong inside which, where a section begins and ends, and where a nesting error has broken the pattern. Without indentation, that tree is invisible, and reading the file becomes an exercise in counting tags.
Consistency matters more than the exact number of spaces. Whether you use two spaces, four spaces, or a tab per level, the important thing is to use the same amount at every level, throughout the file, so that depth is always proportional to indentation. A file that mixes two-space and four-space indentation, or that indents some children but not others, misleads the reader: a deeply indented element may actually be a sibling, and a shallowly indented element may actually be a child. Most editors can enforce a consistent indentation automatically, and using that feature — rather than indenting by hand and by eye — removes a whole class of inconsistencies. Choose a style, configure your editor to use it, and let the tool maintain it.
Indentation also serves as an early warning system for nesting errors. If you indent carefully as you write, a closing tag that does not line up with its opening tag stands out immediately, and a block that is indented one level too deep suggests that an element was not closed where it should have been. That visual feedback is faster than running a validator for every small change, although it does not replace validation. It also helps during debugging: when a layout or script behaves unexpectedly, scanning the indentation often reveals that an element is nested inside the wrong parent, even before you read the tag names closely. In that sense, indentation is not decoration; it is a diagnostic tool built into the way you write.
Finally, indentation is a courtesy to future readers, including yourself. Code is read far more often than it is written, and a file that communicates its structure through indentation is cheaper to maintain, safer to change, and easier for a new team member to understand. The time spent indenting — or configuring an editor to indent for you — is repaid every time someone opens the file and understands it without effort. A well-indented file says, in effect, "I expect this to be read by humans, and I have made that easy." That attitude, applied consistently, distinguishes professional code from code that merely works.
Check: Does indentation change how a browser renders a page?
Section 44 — One page, one job
A well-structured page does one job clearly. Its h1 states that job in a sentence, its sections support that job by breaking it into parts, its links and calls to action serve that job, and nothing unrelated competes for the visitor's attention. A pricing page explains pricing; a tutorial teaches one skill; a product page sells one product. That focus is not a limitation; it is what makes the page usable, because a visitor who arrives with a question can tell within seconds whether this page answers it, and can find the answer without wading through unrelated material. A page that tries to do three jobs at once forces every visitor to do the filtering themselves, and most will simply leave.
The sign that a page should be split is that its sections have stopped supporting a single job and started pursuing separate ones. If a page's outline reads like three different tables of contents stitched together — a tutorial, a product pitch, and a company history, each with its own h1-worthy topic — then the page is really three pages sharing a file. Other signs include a heading outline that cannot be summarised in one sentence, calls to action that point in contradictory directions, and sections that visitors must scroll past to reach the content they came for. When you notice those signs, splitting is not extra work; it is clarifying work, because each new page can then have its own title, its own description, and its own focused outline, which also helps search engines understand and surface each topic separately.
Splitting a page well requires more than cutting it into pieces. Each new page needs its own complete skeleton — its own title, description, h1 and structure — and the pages need to link to each other where a visitor might reasonably want to move from one job to the next. A tutorial page might link to the related product page, and the product page might link back to the tutorial, but neither should contain the other's full content. That linking preserves the visitor's journey without merging the jobs. It also keeps each page's maintenance simpler: updating the tutorial does not risk breaking the product pitch, and vice versa, because they are separate documents with separate concerns.
The one-job principle also applies at smaller scales. A section should do one job within its page, a paragraph should express one idea, and a call to action should ask for one action. That fractal focus — one job at every level — is what makes a page feel clear rather than cluttered, even when it contains a lot of information. When you are tempted to add "just one more thing" to a page, ask whether that thing serves the page's job or starts a new one. If it starts a new one, give it its own page, its own heading, and its own chance to be found. Clarity, in this sense, is not about having less content; it is about giving each piece of content a home where it belongs.
Check: What is the sign that a page should be split?
Section 45 — Document outline exercise
The document outline exercise is a practical test you can apply to any page, yours or someone else's, to judge whether its structure works. Take the page, ignore all of its body text, and write down only its headings, in order, with their levels. Then read that list on its own. If it reads like a sensible table of contents — a clear overall title, followed by major parts, followed by subparts that belong under them — then the document is well structured, because its headings are doing the job of organising the content. If the list reads like a jumble, with orphaned subheadings, skipped levels, or phrases that only make sense with the body text beside them, then the headings are doing decoration rather than structure, and the page needs reworking.
Applying the exercise to a news article is instructive because news pages are often long and complex. A well-structured article might outline as: h1 for the story title, h2 for background, h2 for what happened, h3 for eyewitness accounts under what happened, h2 for reactions, and h2 for what happens next. Each heading belongs under the one above it, and a reader who saw only the outline would know what the article covers and in what order. A poorly structured version of the same article might outline as: h1 for the title, h3 for a sidebar heading used because it looked small, h2 for a pull quote styled as a heading, and h4 for a section that is actually a major part. The outline reveals those errors instantly, in a way that reading the full article might not, because the full text distracts from the structure.
The exercise is also a good revision tool for your own pages. After drafting a page, extract its headings — many editors and browser extensions can do this automatically, or you can simply copy them by hand for a short page — and check three things: that there is one h1, that no level is skipped, and that each heading makes sense without its body text. A heading such as "More" or "Click here" fails the third test, because it tells an outline reader nothing about the section it heads. A heading such as "Pricing for small teams" passes, because it names its topic independently. Rewriting vague headings to be self-explanatory is often the single most effective structural improvement you can make, and it costs no layout changes at all.
Finally, the outline exercise teaches you to think like a visitor who navigates by headings, which is how many screen reader users and many sighted scanners actually use a page. Those visitors do not read linearly from top to bottom; they jump from heading to heading, deciding at each one whether to read the section below it. A good outline therefore serves them directly: it is their navigation system. Practising the exercise on other people's pages — news sites, documentation, blogs — trains your eye to spot good and bad outlines quickly, and that trained eye will improve your own headings long before you need a validator to tell you something is wrong.
Check: What does a good heading outline read like?
Section 46 — Accessibility tree
When a browser loads a page, it builds two related structures from your HTML: the visual rendering that sighted visitors see, and the accessibility tree that assistive technology reads. The accessibility tree is a simplified, semantic version of the document: it contains the roles, names, states and relationships of elements — this is a heading of level two, this is a navigation landmark, this is a button that is currently disabled — but it omits purely presentational details such as colours and exact positions. Screen readers read that tree, not the visual page, and they use it to let visitors navigate by headings, landmarks, links and form controls, to hear the structure of the page, and to interact with it by keyboard. If the tree is good, the page is usable without sight; if the tree is poor, the page may look perfect and still be unusable.
Semantic HTML is what makes the accessibility tree useful, which is why this chapter has emphasised it so heavily. A real heading element becomes a heading node in the tree, with its level, so a screen reader can list all headings and jump between them. A div styled to look like a heading becomes a generic node with no heading role, so it does not appear in that list at all. A nav element becomes a navigation landmark, a main element becomes a main landmark, and a button element becomes a button with an activation behaviour that keyboard users can trigger. None of that requires extra code beyond choosing the right element; the browser derives the tree from the semantics you provide. Conversely, no amount of CSS can add a heading role to a div, because CSS affects presentation, not the tree's semantics, except through a few specific properties that should not be used as a substitute for real semantics.
Alt text for images, covered in Chapter 1 and revisited throughout this book, plays a similar role in the tree: it provides the accessible name for an image node, so a screen reader can announce what the image shows. An image without alt text becomes a node with no name, or is omitted from the tree, leaving a gap in the content. Heading order matters in the tree as well, because the tree preserves the hierarchy: a skipped heading level creates a confusing hierarchy in the tree, just as it does in a printed outline. The tree is therefore not an abstract concept; it is the direct, mechanical consequence of the choices you make in your HTML, and every semantic decision in this chapter can be understood as a decision about what the tree will contain.
You can inspect the accessibility tree yourself using browser developer tools, which show the tree alongside the rendered page and the source. Doing so for your own pages is eye-opening: a page that looks polished may reveal a tree full of generic nodes, missing landmarks, and unnamed controls, while a plain-looking semantic page reveals a clean, navigable tree. Making that inspection part of your testing — checking the tree, not just the screenshot — is a habit that will keep your accessibility work honest, because it measures what assistive technology actually receives, rather than what you intended it to receive.
Check: What does a screen reader actually read — the visual page or the accessibility tree?
Section 47 — Search engines read structure too
Search engines, like screen readers, do not experience a page visually; they parse its HTML, build a model of its structure, and use that model to decide what the page is about, which parts are most important, and when to show it in response to a search. The title element tells them the page's name, the meta description offers a summary for results, headings tell them the topics and subtopics, semantic landmarks tell them which content is central and which is repeated furniture, and links tell them how pages relate to each other. Good structure is therefore also good discoverability, not because of any trick, but because it removes ambiguity about the page's meaning for every automated reader that processes it.
The h1 deserves special attention in this model. A search engine treats the h1 as the primary statement of what the page is about, similar to the title of a book chapter. If the h1 is vague, misleading, or missing, the engine must guess the page's topic from other signals, and that guess may be less accurate than a clear h1 would have been. If the h1 is stuffed with keywords in an unnatural phrase, the engine may recognise the manipulation and discount it. A natural, specific h1 that names the page's single job — the same h1 that serves human visitors in Section 44 — is therefore the best choice for search as well as for people. The interests of human readers and search engines align here, because both want a clear, honest statement of topic.
Headings below the h1 work similarly, at a finer grain. H2 elements signal the page's major topics, and h3 elements signal subtopics, allowing a search engine to understand the page's coverage in detail and to match it to more specific searches. A page whose headings form a clean outline is easier to summarise and to match than a page whose headings are decorative or disordered, because the engine can trust the outline as a map of the content. Semantic elements reinforce that map: content inside main is weighted as central, content inside an article is treated as a distributable item, and content inside a footer is understood as closing information rather than as the page's topic. None of this requires keyword tricks or hidden text; it requires only that the structure honestly reflects the content.
It is important to keep expectations honest. Good structure helps a page be understood and found, but it does not guarantee a top ranking, because ranking also depends on the quality and relevance of the content, on links from other sites, on performance, and on many other factors outside HTML structure. What structure does guarantee is that you are not losing discoverability through ambiguity: a well-structured page gives search engines the best possible chance to understand it correctly. That is a modest, truthful claim, and it is enough reason to structure every page carefully, without resorting to the deceptive techniques that search engines penalise and that readers distrust.
Check: How does a search engine use an h1?
Section 48 — Progressive enhancement, first mention
Progressive enhancement is a strategy for building pages in layers, starting with a foundation that works for everyone and then adding enhancements for browsers and devices that can support them. The foundation is HTML: content marked up semantically, with links that work, forms that submit, and text that reads sensibly on its own. On top of that foundation comes CSS, which adds layout, colour and typography for browsers that support it. On top of CSS comes JavaScript, which adds interactivity and dynamic behaviour for browsers where it runs successfully. Each layer enhances the one below it, but none of them is required for the page's core job to work.
The reason for that order is resilience. Stylesheets can fail to load on a slow connection, JavaScript can fail because of a network error, a browser extension, a syntax error in a script, or a device that does not support a feature. If the page's core content and functionality depend on the failed layer, the page breaks for everyone affected by that failure, even though the underlying content is perfectly available. If the page is built with progressive enhancement, the same failure merely removes an enhancement: the page still displays its content, its links still work, and its forms still submit, albeit in a plainer form. A page that only works with JavaScript is therefore a page that has chosen to break for a predictable fraction of its visitors, rather than degrading gracefully for them.
A concrete example makes the principle clear. A navigation menu built as a list of links inside a nav element works without CSS or JavaScript: the links are visible and clickable, even if they appear as a plain vertical list. CSS can then style that list into a horizontal menu, and JavaScript can add a mobile toggle that collapses it on small screens. If the CSS fails, the menu is plain but usable; if the JavaScript fails, the menu is fully expanded but usable. By contrast, a menu built entirely in JavaScript, where the links are generated by a script and do not exist in the HTML, disappears completely when that script fails, leaving the visitor with no navigation at all. The enhanced version is nicer, but the unenhanced version must exist first.
Progressive enhancement is introduced here, at the end of the structure chapter, because structure is its foundation. You cannot enhance a page that has no semantic foundation to enhance, and you cannot test whether a page works without JavaScript until you have built it in HTML alone. The habit to form now is to build and test each page in that order: write the HTML, check that it works with styles and scripts disabled, then add CSS, then add JavaScript, checking at each step that the previous layer still works. Later chapters will return to this principle repeatedly, because it underpins accessible, resilient front-end work far beyond this chapter's scope.
Check: What should still work if a page's JavaScript fails to load?
Section 49 — Structure before style
Resist the temptation to style a page before its structure is right, because styling first creates rework that structuring first avoids. When you style a div-soup page, you write selectors that target those divs, layout rules that depend on their nesting, and spacing that compensates for missing headings or landmarks. When you later correct the structure — replacing a div with an article, promoting a styled paragraph to a heading, or moving content into main — those selectors break, the layout shifts, and the spacing must be redone. The work you did styling the wrong structure is not merely wasted; it actively obstructs the correction, because you must now untangle styles that were built around a shape that no longer exists.
The correct order — structure first, style second, behaviour third — follows from the layering in Section 48 and from the practical reality of how pages are maintained. Structure is the most stable part of a page: its topics, its outline, and its landmarks change rarely, while its visual design may be refreshed, its layout may be adapted for new devices, and its interactions may be added or removed. Building the stable layer first gives the volatile layers something solid to attach to. A stylesheet written against a stable semantic structure survives a redesign far better than one written against a fragile div structure, because the elements it targets — header, nav, main, article — retain their meaning even when their appearance changes completely.
Styling first also hides structural problems that would otherwise be obvious. A page with no real headings can be made to look well-organised by styling paragraphs to different sizes, and a page with no main landmark can be made to look like it has a clear centre by using colours and spacing. Those visual fixes make the page look finished, which reduces the motivation to fix the underlying structure, while leaving screen reader users, search engines and future maintainers with the same problems as before. A page that is structured first and styled later cannot hide in that way: its unstyled form already reveals whether its outline is clear, whether its landmarks are present, and whether its content reads sensibly, before any visual polish distracts from those questions.
In practice, "structure first" does not mean you must finish all HTML for a whole site before writing any CSS. It means, for each page or component, you should settle its elements, its headings, and its landmarks before you invest in its detailed styling, and you should test that unstyled structure — by reading its outline, by checking it in a screen reader or accessibility tree, and by validating it — before moving on. That sequence takes a little discipline, especially when a visual idea is exciting, but it saves far more time than it costs, because it prevents the most expensive kind of rework: redoing finished work to fit a structure that should have been there from the start.
Check: Why is styling first a waste of effort?
Section 50 — Chapter 2 in one paragraph
A well-structured document is more than a collection of tags in a file; it is a deliberate set of decisions that together give a page its meaning. It begins with a language declaration that tells readers and machines which language the page speaks, and a character encoding that ensures every character displays correctly. It has a specific title that names the page in tabs and search results, a viewport declaration that lets mobile browsers see it at its true size, and a description that summarises it accurately for searchers. Its body is organised into a semantic skeleton — header for introductions, nav for major navigation, main for the single primary content, sections for headed themes, articles for self-contained items, asides for tangential material, and footers for closing information — with divs and spans reserved for the cases where no semantic element fits. Its headings form a clean outline, one h1 followed by h2s and h3s without skipped levels, so that the page's topics can be read as a table of contents. Its paragraphs express one idea each, its quotations, code, abbreviations and dates are marked with the elements that describe them, and its links use correct relative paths, meaningful anchor ids, and safe new-tab practices where needed. That skeleton is validated, indented for human readers, and built to work before any styling or scripting is added, so that browsers, screen readers, search engines and your own CSS all have something solid to work with. Get that skeleton right, and everything you add later — style, behaviour, new content — rests on a foundation that will not need to be rebuilt. This summary is also a checklist you can carry into every page you build from now on. Before you consider a page finished, run through it in your mind: language declared, encoding first in the head, title specific, viewport present, description written for this page, one main, headings in order, sections headed, articles self-contained, asides tangential, footers closing, links correct, code escaped, and the whole document validated. If any item is missing, fix it now, while the page is still small and the fix is cheap, rather than discovering it later when styles and scripts depend on the flawed structure. Use it whenever you start a new page, and revisit it whenever an existing page grows, because structure that was clear at ten sections can become tangled at thirty without a deliberate check. The pages you build in later chapters will be larger and more interactive, but they will all be judged by the same standard introduced here: does the document say what it means, clearly, in its structure alone? A page that passes that test is not merely valid HTML; it is a page that respects its readers, its maintainers, and every tool that will ever process it, and that respect is the real subject of this chapter.
Check: In your own words, what makes a document well structured?
Chapter 2 — Practical task
Take your Chapter 1 introduction page and rebuild its structure properly: add lang="en", a UTF-8 meta tag, a viewport tag, a specific title and a meta description. Replace generic divs with header, nav (even if it only links to sections of the page), main, section and footer elements. Give each section a heading, check the heading order reads like an outline, and run the result through a validator, fixing every error it reports.
Chapter 2 — Chapter questions
- Why does a page need exactly one main element?
- A sidebar of related links: section, aside or div — and why?
- Explain the difference between a section and an article with an example of each.
- What three meta tags should every page have in its head, and what does each do?
- Your headings read: h1, h3, h2, h4. What is wrong, and how do you fix it?