Labelled Boxes: HTML Is Meaning, Not Looks
Every tag you choose is a label that machines will read — the browser, a screen reader, a search crawler, next year's you. "It looks the same" is the most expensive sentence in frontend.
Two pages. On screen they are pixel for pixel identical: same heading, same menu, same three cards, same button.
The first is built from div and span with class names like title, menu, card, btn. The second uses h1, nav, article, button.
Load them both and you cannot tell them apart. Then start using them. On the second, the Tab key walks through the interactive elements and Enter presses the button. On the first, Tab does nothing — a div isn't focusable, so a keyboard user simply cannot reach the button. A screen reader announces the second as "button, Send"; on the first it says nothing at all, because there's nothing to say. A search engine reads the second and finds a heading and an article; on the first it finds a wall of anonymous boxes.
The pixels were the same. Everything underneath was different.
What "semantic" means
HTML has around a hundred elements, and roughly thirty of them do real work. Their names describe role, not appearance: this is a heading, this is a list, this is navigation, this is a button, this is a form field with a label attached to it.
You choose an element the way you'd label a box when moving house. Write "stuff" on all forty boxes and they still hold everything they held before — you've just destroyed the information about what's inside, and the person unloading the van pays for it. div is a box labelled "stuff."
And the readers are more numerous than you think:
- The browser, which gives elements built-in behaviour based on what they are.
- Screen readers and other assistive technology, which navigate by structure — jump to the next heading, list all the links, go to the main region.
- Search engines, which weight and summarise by structure.
- Reader modes, share previews, translation tools, browser autofill — all of which guess from your markup.
- Whoever opens this file in a year, including you, reading a hundred lines to find out where the page's actual content starts.
A
divis a box labelled "stuff." It works, and everyone downstream pays for it.
The behaviour you're throwing away
The most concrete argument is what a real element gives you free.
A button is focusable from the keyboard, fires on both Enter and Space, is announced as a button with its label, can be disabled, and submits a form when it's inside one. To make a clickable div equal to it you need a tabindex, a click handler, a keydown handler that special-cases two keys, an ARIA role, an ARIA disabled state — and you'll still get it subtly wrong.
An a with an href can be opened in a new tab, copied, bookmarked, dragged, previewed on hover and understood by a crawler. A div with a click handler that changes the URL is a link that only works for people using it exactly as you imagined.
The pattern generalises. input type="email" brings a keyboard with an @ on it, browser autofill and free validation. input type="date" brings a date picker built by people who thought about time zones for a living. details and summary give you an accordion with no JavaScript at all. dialog gives you a modal with focus trapping and Escape handling.
Every one of these is behaviour someone already wrote, tested against edge cases you haven't thought of, and shipped in every browser. Choosing the anonymous box means volunteering to rewrite it worse.
Headings are a table of contents
Of everything in this article, this is the piece most often done wrong: headings are not font sizes. They are the document's outline, and assistive technology navigates by them the way you navigate a book by its contents page.
Three rules cover nearly all of it. One h1 per page, naming what the page is. Levels descend without gaps — an h3 sits inside an h2, not directly under an h1 because it looked better small. And nothing becomes a heading by being bold and large, nor stops being one by being styled small.
If your h2 is visually too big, change the CSS. Choosing h4 because it renders at the size you wanted is the exact mistake this article exists to prevent: you've said something false about the structure in order to get a font size.
Landmarks: the shape of the page
Above headings sits a layer describing the page's regions: header, nav, main, footer, aside, article, section.
These are what let a user jump straight to the main content instead of tabbing through forty menu links on every page — the equivalent of the "skip to content" link, except automatic. One main per page. nav for real navigation blocks, not for every group of links. article for something that would still make sense pulled out on its own — a post, a comment, a product card. section only when it has a heading; otherwise it's a div, and that's fine.
Which is worth saying plainly: div and span are not forbidden. They are the correct choice when your only reason for the element is layout or styling — a grid wrapper, a flex row, a bit of text you need to colour. They're wrong only when a meaningful element existed and you passed it over.
The attributes are part of the meaning
Half of semantics lives in attributes, and they're skipped even more often than the elements.
alt on an image states what the image conveys — not "image of a chart" but what the chart says. If the image is purely decorative, an empty alt is the correct answer and tells assistive tech to skip it; leaving the attribute off entirely means the file name gets read aloud instead.
label tied to an input with for is what makes the label clickable and what makes a screen reader say the question when the field is focused. A placeholder is not a label: it vanishes the moment someone types, right when they most need to remember what the field wanted.
lang on the html element tells a screen reader which language to pronounce, and a wrong or missing lang makes Russian text read aloud in an English voice — unintelligible. type on inputs decides the mobile keyboard your user gets. title in the head is the browser tab, the bookmark and the search result.
The browser will "fix" it, quietly
One more thing that saves hours of confusion later. HTML is deliberately forgiving: an unclosed tag, a table cell outside a row, a p containing a div — the parser doesn't refuse, it repairs. And its repairs are not always what you meant.
That's why what you inspect in the developer tools sometimes doesn't match what you typed: you're looking at the DOM the browser built, not your file. When markup misbehaves in ways that make no sense, comparing your file against the actual tree is often the whole diagnosis.
In practice
Learn thirty elements properly, not a hundred shallowly. Headings, paragraph, lists, links, images, the form family, table, and the landmarks. Depth on these thirty is worth more than recognition of a hundred — and recognition is precisely the illusion the How to Learn sphere warns about: skimming a reference list feels like learning and trains nothing but the feeling.
Mark up on paper first. Take a screenshot of any page and, before writing code, write which element each region should be. Two minutes, and it forces the decisions you'd otherwise make accidentally.
Turn the CSS off. In devtools, disable the stylesheets and read your page bare. If the naked document is still comprehensible in the right order, the structure is right. If it turns to soup, your meaning was living in the CSS, where machines can't see it.
Tab through everything. Keyboard only, no mouse, on every page you build. Anything you can't reach or activate is a div pretending to be a control.
Read the accessibility tree. Browser devtools have a panel showing your page as assistive technology sees it. It's the fastest existing feedback loop for this skill, and it converts an abstract rule into something you can check in ten seconds.
Ask "what is this?" before "how should it look?" Every single time. That question, asked consistently for a month, is the whole habit.
Check yourself
Close the article and answer in your own words:
- Name four different consumers of your markup besides the browser's renderer.
- What exactly does a
buttongive you that a clickabledivdoesn't? - Why is choosing a heading level by font size a real error and not a stylistic one?
- When is a
divthe correct choice? - What's the difference between an empty
altand a missingalt? - Why is a placeholder not a substitute for a label?
- Why can the tree in devtools differ from the HTML you wrote?
In short
- Two pages can look identical and behave completely differently: markup is meaning, and meaning is what everything downstream reads.
- Tags name roles, not appearance — and the readers include the browser, assistive tech, search engines, reader modes, autofill and future you.
- Real elements bring free behaviour: focus, keyboard handling, validation, pickers, dialogs. Recreating it on a
divmeans rewriting it worse. - Headings are a table of contents: one
h1, no skipped levels, size decided in CSS. - Landmarks let people jump to the main content instead of tabbing through the menu every time.
divandspanare right when the reason is layout, wrong when a meaningful element existed.- Attributes carry half the meaning:
alt,labelwithfor,lang, inputtype. - The parser repairs broken markup silently, so the DOM you inspect may not match the file you wrote.