Semantic HTML: 10 common mistakes and the tags that fix them

div elements everywhere, b instead of strong, a broken heading hierarchy: ten common HTML mistakes, why they hurt accessibility and SEO, and the semantic tag that fixes each one.

5 common HTML mistakes to avoid, and what to write instead
Quick answer

Semantic HTML means choosing the tag that describes the role of the content (header, nav, main, article, strong, button) rather than a div or a span dressed up with CSS. Screen readers, search engines and browsers rely on these tags to understand the page. The ten mistakes below are the most frequent, and each one has a direct fix.

An HTML page can render perfectly and still be badly written. div everywhere, bold set with b, headings picked for their size: the browser displays it all without complaint, but screen readers, search engines and your colleagues lose the information the tags were supposed to carry. That is what semantic HTML means: using the tag that says what the content is, not just what it should look like. Here are the ten most common mistakes and how to fix them.

Why semantics matter

  • Accessibility. A screen reader offers to jump straight to the navigation, the main content or the footer. It can only do so if nav, main and footer exist. With nothing but div elements, the user hears a flat page.
  • SEO. Search engines rely on structure to identify the main content, the headings and the relationships between sections. A clean hierarchy is understood first time; a soup of div elements has to be guessed at.
  • Maintenance. <nav> reads without a comment; <div class="nv2"> means opening the CSS. Semantic code is still readable six months later.
  • Behaviour for free. A button fires from the keyboard, an a opens in a new tab on middle-click, a label enlarges the clickable area of a checkbox. All of it has to be recoded by hand if you cheat with div elements.

The structure of a page has dedicated tags. A div with the id header is not a header as far as the browser is concerned.

Don’t do this:

html
<div id="header">…</div>
<div id="menu">…</div>
<div id="content">…</div>
<div id="footer">…</div>

Do this:

html
<header>…</header>
<nav aria-label="Navigation principale">…</nav>
<main>…</main>
<footer>…</footer>

Each of these tags carries an implicit role (banner, navigation, main, contentinfo) that assistive technologies recognise. main must be unique on the page; header and footer can be repeated inside an article.

Mistake 2: an image caption in a paragraph

An image and its caption form a unit. The figure tag binds them together, and figcaption holds the caption.

Don’t do this:

html
<img src="montagne.jpg" alt="Le mont Blanc au lever du soleil">
<p>Le mont Blanc, juillet 2026</p>

Do this:

html
<figure>
  <img src="montagne.jpg" alt="Le mont Blanc au lever du soleil">
  <figcaption>Le mont Blanc, juillet 2026</figcaption>
</figure>

figure also suits a code block, a chart or a quotation that comes with a caption.

Mistake 3: b and i for emphasis

b and i describe an appearance. strong and em describe an intention: strong importance, stress on a word. A screen reader may change its intonation on em, never on i.

Don’t do this:

html
<b>Attention</b> : ce réglage est <i>irréversible</i>.

Do this:

html
<strong>Attention</strong> : ce réglage est <em>irréversible</em>.

b and i are not banned: each keeps a precise use, a keyword drawn to the eye without any particular importance for b, a foreign term or the name of a ship for i. If all you want is decorative bold, that is CSS: font-weight: 700.

Mistake 4: a broken heading hierarchy

The h1 to h6 tags form the outline of the document. Choosing an h4 because it is “the right size” breaks that outline: screen readers navigate from heading to heading, and search engines infer the structure from it.

Don’t do this:

html
<h1>Nos services</h1>
<h4>Développement</h4>     <!-- saut de h1 à h4 -->
<h1>Hébergement</h1>       <!-- second h1 pour une sous-partie -->

Do this:

html
<h1>Nos services</h1>
  <h2>Développement</h2>
    <h3>Sites vitrine</h3>
  <h2>Hébergement</h2>

One h1 per page, no skipped level, and the size is set in CSS. If a heading has to look small, that is h2 { font-size: 1.1rem }, not h5.

Mistake 5: section and article confused, or used for everything

article is for self-contained content that would keep its meaning outside the page: a blog post, a comment, a product card. section groups thematic content inside a larger whole, and should always have a heading. A div remains the right choice for a simple layout wrapper.

Don’t do this:

html
<section>
  <section><img src="logo.svg" alt="Gekkode"></section>
  <section>Du texte sans titre</section>
</section>

Do this:

html
<article>
  <h2>Titre du billet</h2>
  <section>
    <h3>Première partie</h3>
    …
  </section>
</article>

<div class="colonnes">…</div> <!-- pure mise en page : div -->

A link (a) takes you somewhere. A button (button) triggers an action: submit, open a menu, show a dialog. An a href="#" with a click handler is neither, and a clickable div is accessible neither from the keyboard nor to screen readers.

Don’t do this:

html
<a href="#" onclick="ouvrirMenu()">Menu</a>
<div class="btn" onclick="envoyer()">Envoyer</div>

Do this:

html
<button type="button" aria-expanded="false" aria-controls="menu">Menu</button>
<button type="submit">Envoyer</button>
<a href="https://www.gekkode.com/en/tarifs/">Voir les tarifs</a>

A native button responds to Enter and Space, receives keyboard focus and announces its role. All of that is lost with a div.

Link text must announce its destination on its own: screen readers offer a list of the page’s links out of context, and search engines use the anchor text to qualify the target page.

Don’t do this:

html
Pour nos tarifs, <a href="https://www.gekkode.com/en/tarifs/">cliquez ici</a>.

Do this:

html
Consultez <a href="https://www.gekkode.com/en/tarifs/">nos tarifs 2026</a>.

Mistake 8: images without alt

The alt attribute describes the image for whoever cannot see it: a screen reader, a browser that failed to load it, a search engine. It is mandatory. A purely decorative image carries an empty alt, not a missing one.

Don’t do this:

html
<img src="graphique-ventes.png">
<img src="separateur.png" alt="separateur.png">

Do this:

html
<img src="graphique-ventes.png" alt="Ventes trimestrielles 2026 : hausse de 12 % au T2">
<img src="separateur.png" alt=""> <!-- décorative : alt vide -->

The file name is never a description. Describe what the image adds to the point being made.

Mistake 9: form fields without a label

Text placed next to a field is not connected to it. The label tag, linked through for and id, announces the field to the screen reader and makes the text clickable to give focus.

Don’t do this:

html
Adresse e-mail <input type="email" name="email">
<input type="text" placeholder="Votre nom">

Do this:

html
<label for="email">Adresse e-mail</label>
<input id="email" type="email" name="email" autocomplete="email">

<label for="nom">Votre nom</label>
<input id="nom" type="text" name="nom" autocomplete="name">

The placeholder is no substitute for the label: it disappears as soon as you type and its contrast is often too low. Other good practices for HTML forms build on this one.

Mistake 10: inline styles and fake lists

Two bad habits that mix structure and presentation. Inline styles stop you changing the look without touching the HTML; a list faked with dashes and br is not a list to the browser, which can neither announce it nor count its items.

Don’t do this:

html
<h1 style="font-size: 24px; color: #333;">Titre</h1>
<p>- Pommes<br>- Poires<br>- Cerises</p>

Do this:

html
<h1 class="titre-page">Titre</h1>
<ul>
  <li>Pommes</li>
  <li>Poires</li>
  <li>Cerises</li>
</ul>
css
.titre-page {
  font-size: 1.5rem;
  color: #333;
}

Checking your HTML

Three quick checks, in this order:

  1. The W3C validator flags unclosed tags, unknown attributes and missing alt attributes.
  2. The Accessibility tab of the developer tools (Chrome, Firefox) shows the tree as a screen reader perceives it: if your header, nav and main appear there as landmarks, the structure is right.
  3. Keyboard navigation: tab through the page. Everything clickable must receive focus, in a logical order. A clickable div fails here.

For the full list of structural and content tags, see 20 HTML5 tags worth knowing. And once the page is structured, CSS takes over, for instance to centre elements without touching the HTML.

Common errors

Replacing every div with section A section without a heading adds nothing and clutters the accessibility tree. A div remains the right choice for a simple layout wrapper.
One main but several header elements A header inside each article is correct; it is main that must be unique and visible.
Believing semantics replace CSS strong is bold by default, but that is a stylesheet accident. Meaning comes from the tag, appearance from the CSS: the two are decided separately.
Forgetting forms The most costly accessibility mistakes are in forms: fields without a label, buttons built from div elements. They are invisible on screen and block keyboard users.

HTML

Damien Flandrin Web developer since 2010, creator of Gekkode and Email Impact. Every article is tested on a real project before publication. Contact
Newsletter

New tests, tutorials and projects, by e-mail.

Reproducible tests, versioned code, dated results. Never any spam.