Se hai usato <div> per tutto — wrapper di pagina, navigazione, contenitore di articolo, sidebar — non sei solo. Era la scelta predefinita per anni. Ma HTML ha avuto elementi semantici propri fin da HTML5, e usarli rende il codice più leggibile, migliore per la SEO e genuinamente più accessibile. Approfondiamo gli elementi che contano davvero.

La parola "semantico" significa semplicemente che l'elemento trasmette un significato oltre alla sua presentazione visiva. Un <div> non significa nulla — è un blocco generico. Un <nav> dice al browser, ai motori di ricerca e alle tecnologie assistive: "questo contiene link di navigazione." Quel contesto non costa nulla da aggiungere e ripaga in molti modi.

Perché la Semantica è Importante

Tre vantaggi concreti, non teorici:

  • SEO. I motori di ricerca usano la struttura del documento per capire la gerarchia dei contenuti. Un elemento <main> segnala il contenuto principale. Un <article> al suo interno segnala un contenuto autonomo. Google usa questi segnali per classificare le pagine.
  • Accessibilità. I lettori di schermo espongono le regioni landmark agli utenti. Con <nav>, <main> e <aside> presenti, gli utenti da tastiera possono saltare direttamente alla sezione desiderata — senza fare tab su ogni link della pagina.
  • Manutenibilità. Un nuovo sviluppatore che legge il tuo template capisce immediatamente la struttura della pagina. <header>/<main>/<footer> si documenta da solo, a differenza di <div class="top">/<div class="content">/<div class="bottom">.

Gli Elementi di Layout Principali

Questi cinque elementi gestiscono lo scheletro esterno della maggior parte delle pagine. Usali in ogni pagina e hai già vinto metà della battaglia semantica:

html
<body>
  <header>
    <a href="/" class="logo">MyBlog</a>
    <nav>
      <ul>
        <li><a href="/articles">Articles</a></li>
        <li><a href="/about">About</a></li>
        <li><a href="/contact">Contact</a></li>
      </ul>
    </nav>
  </header>

  <main>
    <!-- Primary page content goes here -->
  </main>

  <aside>
    <!-- Sidebar: related links, ads, author bio -->
  </aside>

  <footer>
    <p>&copy; 2026 MyBlog. All rights reserved.</p>
  </footer>
</body>
  • <header>. Contenuto introduttivo per la pagina o una sezione. Di solito contiene il logo, il titolo del sito e la navigazione principale. Puoi usarlo anche dentro un <article> per il blocco di intestazione dell'articolo.
  • <nav>. Un insieme di link di navigazione. Non ogni gruppo di link ha bisogno di un <nav> — usalo per i blocchi di navigazione principali come la nav del sito o la paginazione.
  • <main>. Il contenuto dominante della pagina. Deve esserci solo un <main> per pagina e non deve contenere elementi ripetuti tra le pagine (header, nav, footer).
  • <aside>. Contenuto tangenzialmente correlato al contenuto principale. Sidebar, citazioni estratte, articoli correlati. I lettori di schermo lo espongono come landmark complementare.
  • <footer>. Footer per la pagina o una sezione. Può contenere informazioni sul copyright, navigazione secondaria, link di contatto o una breve nota sull'autore.
Errore comune: <header> e <footer> non sono limitati al livello di pagina. Ogni <article> o <section> può avere il proprio <header> e <footer>. Questo è particolarmente utile per le righe con i dati dell'autore nei post del blog e per i metadati a livello di articolo.

article vs section — Quando Usare Ciascuno

Questo è il punto che crea più confusione. La regola empirica che funziona davvero: se il contenuto avrebbe senso se pubblicato autonomamente (ad es. come voce RSS o condiviso su un altro sito), è un <article>. Se ha senso solo come parte di un insieme più grande, è una <section>.

html
<!-- article: self-contained, could stand alone -->
<article>
  <header>
    <h2>Understanding HTTP/2 Push</h2>
    <p>By Alice Chen — <time datetime="2026-03-15">March 15, 2026</time></p>
  </header>
  <p>HTTP/2 Server Push lets the server send resources...</p>
  <footer>
    <p>Tagged: <a href="/tags/http">HTTP</a>, <a href="/tags/performance">Performance</a></p>
  </footer>
</article>

<!-- section: thematic grouping within a page -->
<section>
  <h2>Related Articles</h2>
  <ul>
    <li><a href="/http3-quic">HTTP/3 and QUIC Explained</a></li>
    <li><a href="/cdn-strategy">CDN Strategy for Global Apps</a></li>
  </ul>
</section>

<section> dovrebbe avere sempre un'intestazione (da <h2> a <h6>). Se la tua sezione non ha un'intestazione, di solito è un segnale che dovresti usare un <div>. Lo spec WHATWG è chiaro: <section> è per raggruppamenti tematici, non per divisioni di layout arbitrarie.

figure, figcaption, time e address

Quattro elementi che gli sviluppatori spesso dimenticano ma usano regolarmente:

html
<!-- figure + figcaption: images, code blocks, diagrams, charts -->
<figure>
  <img src="/images/latency-chart.png" alt="P99 latency over 24 hours showing a spike at 14:30">
  <figcaption>Figure 1: API latency during the Tuesday incident (UTC).</figcaption>
</figure>

<!-- A code block as a figure (totally valid) -->
<figure>
  <pre><code>const result = await db.query('SELECT * FROM users WHERE active = true');</code></pre>
  <figcaption>Listing 1: Basic active user query.</figcaption>
</figure>

<!-- time: machine-readable dates and times -->
<p>Published <time datetime="2026-04-16T09:00:00Z">April 16, 2026</time></p>
<p>Sale ends in <time datetime="PT2H30M">2 hours 30 minutes</time></p>

<!-- address: contact info for nearest article or body ancestor -->
<address>
  Written by <a href="mailto:[email protected]">Alice Chen</a>.<br>
  123 Dev Street, San Francisco, CA.
</address>
  • <figure>. Qualsiasi contenuto autonomo referenziato dal flusso principale — immagini, listati di codice, grafici, video. Il punto chiave: potrebbe essere spostato in appendice senza interrompere il flusso di lettura.
  • <figcaption>. La didascalia per un <figure>. Deve essere il primo o l'ultimo figlio di <figure>. Fornisce un'associazione semantica tra didascalia e contenuto che un <p> sotto un'immagine non offre.
  • <time>. Date leggibili dagli esseri umani con un attributo datetime leggibile dai computer. Il valore di datetime usa il formato ISO 8601. I motori di ricerca lo usano per i markup di eventi e i segnali di freschezza.
  • <address>. Informazioni di contatto per l'antenato <article> più vicino (o l'intero <body>). Non è un elemento indirizzo generico — è specifico per le informazioni di contatto dell'autore del contenuto o del proprietario del sito.

L'Anti-Pattern della Divite

La "divite" è ciò che accade quando ogni elemento nel tuo HTML è un <div>. Ecco un confronto prima/dopo che mostra il problema:

html
<!-- Before: divitis -->
<div class="page">
  <div class="header">
    <div class="brand">TechBlog</div>
    <div class="nav">
      <div class="nav-item"><a href="/posts">Posts</a></div>
    </div>
  </div>
  <div class="post">
    <div class="post-title">Why TypeScript Is Worth It</div>
    <div class="post-meta">By Bob — Jan 2026</div>
    <div class="post-body">TypeScript adds static types to JavaScript...</div>
  </div>
</div>

<!-- After: semantic HTML -->
<body>
  <header>
    <span class="brand">TechBlog</span>
    <nav>
      <a href="/posts">Posts</a>
    </nav>
  </header>
  <main>
    <article>
      <header>
        <h1>Why TypeScript Is Worth It</h1>
        <p>By Bob — <time datetime="2026-01-10">January 10, 2026</time></p>
      </header>
      <p>TypeScript adds static types to JavaScript...</p>
    </article>
  </main>
</body>

La versione semantica è in realtà più breve, richiede meno nomi di classi CSS e fornisce a browser e strumenti assistivi tutto il necessario per capire la struttura della pagina. Puoi comunque stilizzare tutto esattamente nello stesso modo con CSS — gli elementi semantici non impongono alcun vincolo visivo.

Ruoli ARIA — Ultima Risorsa, Non Prima Mossa

I ruoli ARIA ti permettono di aggiungere significato semantico a elementi che non ce l'hanno nativamente. Il problema è che gli sviluppatori spesso ricorrono ad ARIA quando un elemento HTML semantico farebbe il lavoro meglio. La prima regola di ARIA: non usare ARIA se puoi usare HTML nativo.

html
<!-- Wrong: using ARIA where native HTML works -->
<div role="navigation">
  <a href="/home">Home</a>
</div>

<!-- Right: just use the semantic element -->
<nav>
  <a href="/home">Home</a>
</nav>

<!-- ARIA is appropriate here: custom widget with no HTML equivalent -->
<div
  role="tablist"
  aria-label="Code examples"
>
  <button role="tab" aria-selected="true" aria-controls="panel-js">JavaScript</button>
  <button role="tab" aria-selected="false" aria-controls="panel-py">Python</button>
</div>

Usa ARIA per widget interattivi che l'HTML nativo non copre — pannelli a schede, combobox, visualizzazioni ad albero, selettori di date. Per landmark strutturali come navigazione, intestazioni e contenuto principale, affidati sempre agli elementi nativi.

Struttura Completa di una Pagina Blog

Ecco come appare una pagina blog completamente semantica. Questo è il pattern usato sui siti che ottengono buoni risultati nei controlli di accessibilità senza sforzo aggiuntivo:

html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Why TypeScript Is Worth It — TechBlog</title>
</head>
<body>
  <header>
    <a href="/" class="logo">TechBlog</a>
    <nav aria-label="Site navigation">
      <ul>
        <li><a href="/posts">Posts</a></li>
        <li><a href="/topics">Topics</a></li>
        <li><a href="/about">About</a></li>
      </ul>
    </nav>
  </header>

  <main>
    <article>
      <header>
        <h1>Why TypeScript Is Worth It</h1>
        <address>
          By <a rel="author" href="/authors/bob">Bob Martinez</a>
        </address>
        <p>Published <time datetime="2026-01-10">January 10, 2026</time></p>
      </header>

      <section>
        <h2>The Setup Cost Is Real but Front-Loaded</h2>
        <p>TypeScript adds a compilation step and requires type annotations...</p>

        <figure>
          <pre><code>interface User {
  id: number;
  name: string;
  email: string;
}</code></pre>
          <figcaption>Listing 1: A typed User interface catches shape errors at compile time.</figcaption>
        </figure>
      </section>

      <section>
        <h2>Where TypeScript Pays Off</h2>
        <p>The ROI kicks in as team size and codebase complexity grows...</p>
      </section>

      <footer>
        <p>
          Tagged: <a href="/tags/typescript">TypeScript</a>,
          <a href="/tags/javascript">JavaScript</a>
        </p>
      </footer>
    </article>

    <aside aria-label="Related articles">
      <h2>You Might Also Like</h2>
      <ul>
        <li><a href="/ts-vs-js">TypeScript vs JavaScript — A Practical Comparison</a></li>
        <li><a href="/ts-generics">TypeScript Generics Explained</a></li>
      </ul>
    </aside>
  </main>

  <footer>
    <nav aria-label="Footer navigation">
      <a href="/privacy">Privacy</a>
      <a href="/terms">Terms</a>
    </nav>
    <p><small>&copy; 2026 TechBlog</small></p>
  </footer>
</body>
</html>

Nota il doppio uso di <header> e <footer> — una volta al livello di pagina, una volta dentro <article>. È intenzionale e corretto. Nota anche due elementi <nav> con valori aria-label distinti — questo evita che i lettori di schermo elenchino due identiche regioni di "navigazione".

Riferimento Rapido: Strumenti Utili

Se stai lavorando con HTML e vuoi ripulire o validare il tuo markup, HTML Formatter abbellirà e sistemerà il tuo codice, e HTML Validator individua errori strutturali come tag non chiusi e attributi richiesti mancanti. Per un'analisi di accessibilità più approfondita, web.dev/accessibility offre ottimi strumenti diagnostici e spiegazioni.

Conclusione

L'HTML semantico non riguarda il seguire regole per il gusto di farlo — si tratta di scrivere codice che comunica chiaramente a browser, motori di ricerca, strumenti assistivi e al prossimo sviluppatore che leggerà il tuo template. Gli elementi principali sono semplici: <header>, <nav>, <main>, <article>, <section>, <aside> e <footer> coprono la stragrande maggioranza delle strutture di pagina reali. Aggiungi <figure>, <time> e <address> dove si adattano, ricorri ad ARIA solo quando l'HTML nativo non è sufficiente, e avrai un markup che è davvero un piacere lavorarci.