Si llevas tiempo usando <div> para todo — el contenedor de la página, la navegación, el contenedor del artículo, la barra lateral — no eres el único. Era el movimiento por defecto durante años. Pero HTML tiene elementos semánticos apropiados desde HTML5, y usarlos hace que tu código sea más fácil de leer, mejor para el SEO y genuinamente más accesible. Vamos a analizar los elementos que realmente importan.

La palabra "semántico" simplemente significa que el elemento transmite significado más allá de su presentación visual. Un <div> no significa nada — es un bloque genérico. Un <nav> le indica al navegador, a los motores de búsqueda y a las tecnologías de asistencia: "esto contiene enlaces de navegación." Ese contexto no cuesta nada añadir y rinde de múltiples formas.

Por qué importa la semántica

Tres beneficios reales, no teóricos:

  • SEO. Los motores de búsqueda utilizan la estructura del documento para entender la jerarquía del contenido. Un elemento <main> señala el contenido principal. Un <article> dentro de él señala una pieza independiente. Google usa estas señales al clasificar las páginas.
  • Accesibilidad. Los lectores de pantalla exponen las regiones de referencia a los usuarios. Con <nav>, <main> y <aside> en su lugar, los usuarios de teclado pueden saltar directamente a la sección que desean — sin tener que tabular por cada enlace de la página.
  • Mantenibilidad. Un nuevo desarrollador que lee tu plantilla entiende instantáneamente la estructura de la página. <header>/<main>/<footer> se documenta solo de una manera en que <div class="top">/<div class="content">/<div class="bottom"> no lo hace.

Los elementos de diseño principales

Estos cinco elementos conforman el esqueleto externo de la mayoría de las páginas. Úsalos en cada página y ya habrás ganado la mitad de la batalla semántica:

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>. Contenido introductorio para la página o una sección. Normalmente contiene el logo, el título del sitio y la navegación principal. También puedes usarlo dentro de <article> para el bloque de encabezado propio del artículo.
  • <nav>. Un conjunto de enlaces de navegación. No todos los grupos de enlaces necesitan un <nav> — úsalo para bloques de navegación principales como la navegación del sitio o la paginación.
  • <main>. El contenido dominante de la página. Solo debe haber un <main> por página, y no debe contener nada que se repita en todas las páginas (cabecera, nav, pie de página).
  • <aside>. Contenido tangencialmente relacionado con el contenido principal. Barras laterales, citas destacadas, artículos relacionados. Los lectores de pantalla lo exponen como un punto de referencia complementario.
  • <footer>. Pie de página para la página o una sección. Puede contener información de copyright, nav secundaria, enlaces de contacto o una breve nota del autor.
Error común: <header> y <footer> no están restringidos al nivel de página. Cada <article> o <section> puede tener su propio <header> y <footer>. Esto es especialmente útil para las líneas de firma de las publicaciones del blog y los metadatos a nivel de artículo.

article vs section — Cuándo usar cada uno

Este es el que más confunde a la gente. La regla práctica que realmente funciona: si el contenido tendría sentido si lo sindicases de forma independiente (por ejemplo, publicado como entrada RSS o compartido en otro sitio), es un <article>. Si solo tiene sentido como parte de un todo mayor, es 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>

Una <section> siempre debe tener un encabezado (<h2> hasta <h6>). Si tu sección no tiene encabezado, generalmente es una señal de que deberías usar un <div> en su lugar. La especificación WHATWG es clara al respecto: <section> es para agrupaciones temáticas, no para divisiones de diseño arbitrarias.

figure, figcaption, time y address

Cuatro elementos que los desarrolladores a menudo pasan por alto pero necesitan con frecuencia:

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>. Cualquier contenido independiente referenciado desde el flujo principal — imágenes, listados de código, gráficos, vídeos. La clave: podría moverse a un apéndice sin interrumpir la lectura.
  • <figcaption>. El pie de figura de un <figure>. Debe ser el primer o último hijo de <figure>. Proporciona una asociación semántica entre el pie y el contenido que un <p> debajo de una imagen no ofrece.
  • <time>. Fechas legibles por humanos con un atributo datetime legible por máquinas. El valor datetime usa el formato ISO 8601. Los motores de búsqueda lo usan para el marcado de eventos y las señales de actualidad.
  • <address>. Información de contacto para el ancestro <article> más cercano (o todo el <body>). No es un elemento de dirección de propósito general — es específicamente para la información de contacto del autor del contenido o del propietario del sitio.

El antipatrón "divitis"

La "divitis" es lo que ocurre cuando cada elemento de tu HTML es un <div>. Aquí tienes un antes/después real que muestra el 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 versión semántica es en realidad más corta, requiere menos nombres de clases CSS, y le da a los navegadores y las herramientas de asistencia todo lo que necesitan para entender la estructura de la página. Puedes seguir aplicando exactamente el mismo estilo con CSS — los elementos semánticos no imponen ninguna restricción visual.

Roles ARIA — Un último recurso, no el primer paso

Los roles ARIA te permiten añadir significado semántico a elementos que no lo tienen de forma nativa. El problema es que los desarrolladores a menudo recurren a ARIA cuando un elemento HTML semántico haría el trabajo mejor. La primera regla de ARIA: no uses ARIA si puedes usar 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 para widgets interactivos que el HTML nativo no cubre — paneles de pestañas, comboboxes, vistas de árbol, selectores de fecha. Para los puntos de referencia estructurales como la navegación, los encabezados y el contenido principal, apóyate siempre en los elementos nativos.

Estructura completa de una página de artículo de blog

Así es como se ve una página de artículo de blog completamente semántica. Este es el patrón utilizado en sitios que obtienen buenas puntuaciones en las auditorías de accesibilidad sin esfuerzo adicional:

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>

Observa el doble uso de <header> y <footer> — una vez a nivel de página, una vez dentro de <article>. Eso es intencional y correcto. También observa dos elementos <nav> con valores aria-label distintos — esto evita que los lectores de pantalla listen dos regiones de "navegación" idénticas.

Referencia rápida: herramientas útiles

Si trabajas con HTML y quieres limpiar o validar tu marcado, el Formateador HTML embellecerá y ordenará tu código, y el Validador HTML detectará errores estructurales como etiquetas no cerradas y atributos obligatorios faltantes. Para una auditoría de accesibilidad más profunda, web.dev/accessibility tiene excelentes diagnósticos y explicaciones.

Conclusión

El HTML semántico no se trata de seguir reglas por el mero hecho de seguirlas — se trata de escribir código que comunique claramente a los navegadores, los motores de búsqueda, las herramientas de asistencia y al próximo desarrollador que lea tu plantilla. Los elementos principales son sencillos: <header>, <nav>, <main>, <article>, <section>, <aside> y <footer> cubren la abrumadora mayoría de las estructuras de página reales. Añade <figure>, <time> y <address> donde encajen, recurre a ARIA solo cuando el HTML nativo se quede corto, y tendrás un marcado que es genuinamente un placer trabajar con él.