Fase 1 · Sesión 1

HTML Semántico

El esqueleto de toda web. Aprenderás a escribir HTML que los navegadores, motores de búsqueda y lectores de pantalla realmente entienden.

⏱ 2 horas 📖 Teoría + práctica ♿ Accesibilidad

Al terminar vas a saber

No es solo HTML. Es comunicación.

El HTML que escribes lo leen tres tipos de "usuarios": el navegador, los motores de búsqueda (Google) y los lectores de pantalla (para personas con discapacidad visual). Si usas <div> para todo, solo el humano frente a la pantalla entiende algo. Los otros dos están en la oscuridad.

🔍

Google

Los robots de indexación entienden <article> pero no saben qué es un <div class="post">. HTML semántico mejora directamente tu posicionamiento en buscadores.

Lectores de pantalla

JAWS, NVDA, VoiceOver leen el HTML en voz alta. Con <button> saben que es interactivo. Con un <div onclick> no anuncian nada. Hay 285 millones de personas con discapacidad visual.

👥

Otros desarrolladores

Código semántico es código mantenible. Cuando un compañero lee tu HTML entiende la estructura sin leer el CSS. Eso ahorra horas en equipos reales.

La anatomía de cualquier web

Toda página web bien construida tiene la misma estructura. No como convención, sino porque así funciona el modelo semántico de HTML5.

<!DOCTYPE html>
<html lang="es">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta name="description" content="Descripción de la página para Google">
  <title>Mi sitio — Título para la pestaña y Google</title>
  <link rel="stylesheet" href="styles.css">
</head>
<body>

  <header>          <!-- Cabecera del sitio -->
    <nav>           <!-- Navegación principal -->
      <a href="/">Inicio</a>
      <a href="/about">Sobre mí</a>
    </nav>
  </header>

  <main>            <!-- Contenido principal (ÚNICO en la página) -->
    <section>       <!-- Sección temática con su propio heading -->
      <h1>Título principal de la página</h1>
      <p>Contenido...</p>
    </section>

    <aside>         <!-- Contenido relacionado pero secundario -->
      <h2>Artículos relacionados</h2>
    </aside>
  </main>

  <footer>          <!-- Pie de página -->
    <p>&copy; 2024 Mi sitio</p>
  </footer>

</body>
</html>
<header> Cabecera del sitio o de una sección (article/section) Puede haber varios en la página, pero solo uno para el sitio
<nav> Bloques de navegación principal o secundaria Solo los links de navegación importantes, no todos los links
<main> El contenido único y principal de la página Solo UNO por página. Nunca dentro de header, footer o aside
<section> Agrupación temática de contenido con su propio heading Si no tiene un heading, probablemente sea un div
<article> Contenido independiente y redistribuible: post, producto, comentario ¿Tiene sentido solo, fuera de contexto? Entonces es article
<aside> Contenido relacionado pero secundario: sidebars, anuncios, widgets No es solo "barra lateral". Es contenido opcionalmente relacionado
<footer> Pie de sitio o de una sección Puede contener copyright, links secundarios, contact info
<h1>–<h6> Jerarquía de headings del contenido Un solo h1 por página. No saltes niveles (h1 → h3)

La pregunta que confunde a todos

Estos tres elementos se confunden constantemente. Aquí la regla simple: pregúntate qué es el contenido, no cómo se ve visualmente.

¿Es contenido independiente?

<article>

Un post, una tarjeta de producto, un comentario. Puede vivir fuera de la página y tener sentido completo.

→ Cada tweet en un feed
→ Cada card de producto
→ Cada post de blog
→ Cada comentario en un foro

¿Es una sección temática con heading?

<section>

Agrupa contenido relacionado bajo un tema. Siempre debe tener un heading (h2, h3...) que lo identifique.

→ <section id="features">
→ <section id="testimonios">
→ <section id="precios">
→ <section id="contacto">

¿Es solo un contenedor para CSS/JS?

<div>

Cuando no hay significado semántico. Solo para agrupar cosas por motivos visuales o de JavaScript.

→ <div class="flex-container">
→ <div class="modal-overlay">
→ <div class="grid-wrapper">
→ <div id="app">

Regla práctica: ¿Puedo copiar este bloque de HTML y pegarlo en otra página y que tenga sentido? Si sí → <article>. ¿Tiene un título propio que describe su tema? → <section>. ¿No tiene ningún significado semántico propio? → <div>.

Formularios: el elemento más mal usado de HTML

Los formularios son donde más errores semánticos se acumulan. Un formulario correcto funciona sin JavaScript, es accesible por teclado y tiene validación nativa del navegador.

❌ Formulario incorrecto
<div class="form">
  <div>Nombre:</div>
  <input type="text"
         placeholder="Tu nombre">

  <div>Email:</div>
  <input type="text"
         placeholder="tu@email.com">

  <div onclick="sendForm()">
    Enviar
  </div>
</div>
  • Sin <form>: no funciona con Enter, sin submit nativo
  • Texto sin <label>: lectores de pantalla ciegos al input
  • type="text" para email: sin validación de formato
  • <div onclick> como botón: no funciona con teclado
✓ Formulario correcto
<form action="/subscribe" method="POST">
  <label for="nombre">
    Nombre completo
    <span aria-hidden="true">*</span>
  </label>
  <input
    type="text"
    id="nombre"
    name="nombre"
    required
    autocomplete="name"
    placeholder="Ej: Ana García"
  >

  <label for="email">Email</label>
  <input
    type="email"
    id="email"
    name="email"
    required
    autocomplete="email"
  >

  <button type="submit">
    Suscribirse
  </button>
</form>
  • <form> correcto: submit con Enter, semántica completa
  • <label for> vinculado al id del input
  • type="email" valida formato en navegador y móvil
  • <button type="submit">: accesible por teclado
type="text" Texto genérico autocomplete="name"
type="email" Email (valida @ en móvil/desktop) autocomplete="email"
type="password" Contraseña (oculta el texto) autocomplete="current-password"
type="number" Números con min/max/step min="0" max="100"
type="tel" Teléfono (teclado numérico en móvil) autocomplete="tel"
type="date" Selector de fecha nativo min="2024-01-01"
type="checkbox" Opción múltiple checked para preseleccionar
type="radio" Opción única del grupo name agrupa los radios
type="file" Subida de archivos accept=".pdf,.jpg"
type="range" Slider numérico min max step value
type="search" Campo de búsqueda Semántica para buscadores
type="url" URL (valida formato http://) autocomplete="url"

Accesibilidad: código para todos

No es un extra. En muchos países es un requisito legal. Y mejora tu SEO. Los tres atributos que más diferencia hacen:

alt en imágenes

El texto que se muestra cuando la imagen no carga y que leen los lectores de pantalla. Si la imagen es decorativa, usa alt vacío para que el lector de pantalla la ignore completamente.

<!-- Imagen informativa: describe el contenido -->
<img src="equipo.jpg"
     alt="El equipo de Vitesse Stack en la oficina de Bogotá">

<!-- Imagen decorativa: alt vacío, no se anuncia -->
<img src="decoracion.svg" alt="">

<!-- Icono con función: describe la acción, no el icono -->
<button>
  <img src="search.svg" alt="Buscar">
</button>

aria-label y aria-describedby

Cuando el elemento visual no tiene texto visible suficiente para describirse, estos atributos proporcionan el nombre o descripción accesible al árbol de accesibilidad.

<!-- Botón con solo icono -->
<button aria-label="Cerrar modal">
  <svg><!-- icono X --></svg>
</button>

<!-- Input con descripción adicional -->
<label for="pwd">Contraseña</label>
<input type="password" id="pwd"
       aria-describedby="pwd-hint">
<p id="pwd-hint">
  Mínimo 8 caracteres, una mayúscula y un número.
</p>

<!-- Región con label -->
<nav aria-label="Navegación principal">
  <a href="/">Inicio</a>
</nav>

Jerarquía de headings

Google y los lectores de pantalla usan los headings para construir el índice de la página. La jerarquía debe ser lógica, nunca saltar niveles.

❌ Incorrecto
h1 — Título del sitio
  h3 — ¡Saltamos h2!
    h2 — ¡Volvemos atrás!
  h4 — Sub-sub
✓ Correcto
h1 — Título del sitio (solo uno)
  h2 — Sección principal
    h3 — Subsección
    h3 — Subsección
  h2 — Otra sección principal

Meta tags: lo que Google y las redes sociales leen

El <head> no es solo para el <title>. Estos meta tags afectan directamente cómo aparece tu web en Google y cómo se ve al compartirla en WhatsApp, Twitter o LinkedIn.

<head>
  <!-- BÁSICOS (siempre) -->
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta name="description" content="Descripción de 150-160 caracteres para Google">
  <title>Nombre de la página — Nombre del sitio</title>
  <link rel="canonical" href="https://misitioweb.com/esta-pagina/">

  <!-- OPEN GRAPH (WhatsApp, Facebook, LinkedIn) -->
  <meta property="og:title" content="Título al compartir">
  <meta property="og:description" content="Descripción al compartir">
  <meta property="og:image" content="https://misitioweb.com/preview.jpg">
  <meta property="og:url" content="https://misitioweb.com/esta-pagina/">
  <meta property="og:type" content="website">

  <!-- TWITTER CARD -->
  <meta name="twitter:card" content="summary_large_image">
  <meta name="twitter:title" content="Título para Twitter">
  <meta name="twitter:image" content="https://misitioweb.com/preview.jpg">
</head>

La imagen de og:image debe tener al menos 1200×630px para verse bien en todas las redes. Usa ogp.me para previsualizar cómo se verá tu enlace antes de publicarlo.

Ejercicio: estructura semántica de un blog

Construirás el HTML completo de un blog de tecnología. Sin CSS, sin JavaScript. Solo HTML semántico correcto. El objetivo es que sea perfectamente accesible y que Google entienda la estructura.

1:30

Blog de tecnología con 3 artículos

Un header con nav, un main con section para artículos destacados, cada artículo como article con h2, byline, resumen y link de lectura. Un aside con categorías. Un footer con copyright y links secundarios.

01

Estructura base

DOCTYPE, html con lang="es", head completo con meta description y title descriptivo. No hay CSS todavía.

15 min
02

Header y navegación

header con el nombre del blog, nav con los links principales (Inicio, Categorías, Sobre mí). Usa aria-label en el nav.

15 min
03

Main con artículos

main > section con h1, luego tres article anidados. Cada article tiene h2, p.byline (autor, fecha), p.resumen, y a "Leer más" con aria-label descriptivo.

30 min
04

Aside y footer

aside con h2 "Categorías" y lista de links. footer con dirección, copyright y nav secundario para links legales.

15 min
05

Validación

Pega tu HTML en validator.w3.org y corrige todos los errores. Luego instala el Chrome extension "axe DevTools" y ejecuta el audit de accesibilidad.

15 min

Recursos de esta sesión

Todo lo que necesitas para profundizar después de la clase.