From n00b to ZeroCool / Origen

HTML: la estructura del mundo web (sin humo)

Aprende HTML bien: semántica, accesibilidad, headings y forms. Layout base y cómo llevarlo a React + Vite + Tailwind sin div-soup.

Lo que vale la pena leer aquí

Te pasa: abres DevTools porque “se rompió el diseño”, y lo que encuentras no es un bug… es un cementerio de <div.

Te pasa: abres DevTools porque “se rompió el diseño”, y lo que encuentras no es un bug… es un cementerio de <div>.

Todo “jala” hasta que llega el primer cambio: el banner nuevo del cliente, el modal que pidió tu PM a las 6:40 pm, o el login que alguien metió en un iframe (sí, todavía pasa). Ahí cae el veinte: sin HTML bien armado, el CSS se vuelve talacha eterna, y React nomás maquilla el caos.

HTML no es “lo básico que ya me sé”. Es el plano. El esqueleto. La forma en la que el navegador, Google, lectores de pantalla y tu yo del futuro entienden qué demonios está pasando.

Si alguna vez te tocó hacer un deploy tarde en una laptop viejita con el ventilador sonando como turbina, sabes que lo último que quieres es pelearte con markup sin sentido.

Qué te vas a llevar

  • Cómo pensar HTML como estructura (no como lista de etiquetas para memorizar).
  • La diferencia práctica entre semántica (qué es) y presentación (cómo se ve).
  • Un layout base real: header/nav/main/aside/footer + secciones.
  • Patrones de formularios que no se rompen en production (labels, errores, autocomplete, tipos correctos).
  • Cómo conectar esto con un stack moderno: React con Vite + Tailwind sin caer en div-soup.

Contexto real (el jale no viene “perfecto”)

Muchas chambas web arrancan así:

  • “Es un landing rápido para mañana” (y en dos semanas ya trae checkout, chat, píxel y CRM).
  • “Solo hazlo responsive” (y el diseño llega en una captura de WhatsApp, recortada, con letra chiquita).
  • “Es un cambio mínimo” (y termina siendo refactor porque nadie entiende qué contenedor manda).

Cuando el proyecto crece, el costo no es “volver a escribir HTML”. El golpe real es:

  • CSS frágil: cambias una cosa y se mueve todo.
  • Componentes React con div dentro de div dentro de div y ya nadie sabe dónde está el layout bueno.
  • Accesibilidad rota: teclado que no navega, botones “sin nombre”, headings hechos al aventón… y te enteras cuando cae un ticket con urgencia.

HTML semántico te compra algo bien valioso: margen de maniobra. Ese margen que necesitas cuando el deadline no perdona y nadie quiere hacer rollback.

Guía principal: HTML como estructura (paso a paso)

1) Empieza por el “mapa” de la página, no por el pixel

Antes del Tailwind y antes del “que se vea bonito”, define bloques con intención:

  • Header: identidad + navegación principal.
  • Main: contenido único de esa vista.
  • Footer: enlaces secundarios, legales, contacto.

Esqueleto mínimo (bien armado):

<!doctype html>
<html lang="es-MX">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>Byte IT — Demo</title>
    <meta name="description" content="Ejemplo de estructura HTML semántica" />
  </head>
  <body>
    <a href="#contenido" class="skip-link">Saltar al contenido</a>

    <header>
      <div class="brand">
        <a href="/" aria-label="Inicio">
          <img src="/logo.svg" alt="Byte IT" width="120" height="32" />
        </a>
      </div>

      <nav aria-label="Navegación principal">
        <ul>
          <li><a href="#features">Features</a></li>
          <li><a href="#precios">Precios</a></li>
          <li><a href="#faq">FAQ</a></li>
        </ul>
      </nav>
    </header>

    <main id="contenido">
      <h1>Una página que no se rompe con el primer cambio</h1>

      <section id="features" aria-labelledby="features-title">
        <h2 id="features-title">Features</h2>
        <article>
          <h3>Rápido</h3>
          <p>Contenido…</p>
        </article>
      </section>
    </main>

    <footer>
      <small>© 2026 Byte IT</small>
    </footer>
  </body>
</html>

Decisión práctica: si algo es “la navegación”, que sea <nav>. Si algo es “el contenido principal”, que viva en <main>. No es por purismo; es para que herramientas y personas entiendan tu UI sin adivinar.

2) Semántica: usa la etiqueta que describe el rol

Esto no va de “cambiar div por etiqueta fancy”. Va de darle sentido al DOM:

  • <button> para acciones (abre modal, guarda, envía).
  • <a> para navegación (te lleva a otra ruta/URL/fragmento).
  • <article> para unidades que podrían vivir solas (post, tarjeta de producto, comentario).
  • <section> para agrupar contenido con un heading.

Anti-pattern clásico (y luego te preguntas por qué no funciona igual con teclado):

<div class="btn" onclick="comprar()">Comprar</div>

Mejor:

<button type="button">Comprar</button>

Consecuencia real: el div no trae comportamiento accesible por default, no anuncia su rol a lectores de pantalla y te obliga a reimplementar cosas que el navegador ya resuelve.

3) Headings: tu índice mental (y el de Google)

Si tu página fuera un PDF, los headings son la tabla de contenido. Mantén jerarquía:

  • Un solo <h1> por vista.
  • Secciones principales con <h2>.
  • Subtemas con <h3>.

Mal (por “se ve bonito”):

<h4>Bienvenido</h4>
<h2>Detalles</h2>
<h1>Producto</h1>

Bien (por estructura):

<h1>Producto</h1>
<h2>Detalles</h2>
<h2>Opiniones</h2>
  <h3>Lo mejor</h3>

Regla de oro: si necesitas otro tamaño, ajusta con CSS/Tailwind. No uses headings como control de estilo.

4) Imágenes: alt no es decoración, es contenido alterno

  • Si la imagen aporta info: alt describe lo esencial.
  • Si es decorativa: alt="" (vacío) para que lectores la ignoren.

Ejemplos:

<img src="/promo.jpg" alt="Promoción: 2x1 en planes por tiempo limitado" />

Decorativa:

<img src="/wave.svg" alt="" aria-hidden="true" />

Tradeoff real: escribir alt decente te toma 10 segundos. Te puede ahorrar horas cuando llega auditoría o cuando un cliente “enterprise” pide accesibilidad sin avisar.

  • Link: cambia de página/ruta o apunta a un recurso.
  • Button: dispara una acción.

Esto evita cosas como:

  • Un “link” que no se puede abrir en nueva pestaña.
  • Un “button” que navega y rompe el historial.

6) Formularios que no dan pena en production

Los forms se rompen el día que metes validación, analytics y errores del backend. Si lo armas bien desde el setup, respiras:

  • label asociado (for + id).
  • type correcto (email, password, tel).
  • autocomplete para UX real (y menos fricción).
  • Mensajes de error conectados con aria-describedby.

Ejemplo sólido:

<form>
  <div>
    <label for="email">Correo</label>
    <input
      id="email"
      name="email"
      type="email"
      inputmode="email"
      autocomplete="email"
      required
      aria-describedby="email-help email-error"
    />
    <p id="email-help">Usa el correo con el que te registraste.</p>
    <p id="email-error" role="alert" hidden>
      Ese correo no es válido.
    </p>
  </div>

  <button type="submit">Entrar</button>
</form>

Momento real: cuando alguien te dice “en iPhone el autocomplete no jala”, muchas veces es por name raros o por no declarar autocomplete. El navegador no adivina.

7) El puente a React + Vite + Tailwind (sin div-soup)

En React es facilísimo caer en “todo es un componente” y terminar con puros wrappers sin significado. La idea es mantener semántica desde el JSX.

Ejemplo de layout en React:

export function AppLayout({ children }) {
  return (
    <div className="min-h-dvh bg-slate-950 text-slate-50">
      <a
        href="#contenido"
        className="sr-only focus:not-sr-only focus:absolute focus:top-2 focus:left-2 focus:rounded focus:bg-white focus:px-3 focus:py-2 focus:text-slate-900"
      >
        Saltar al contenido
      </a>

      <header className="border-b border-white/10">
        <div className="mx-auto flex max-w-5xl items-center justify-between px-4 py-4">
          <a href="/" className="font-semibold">Byte IT</a>
          <nav aria-label="Navegación principal">
            <ul className="flex gap-4 text-sm text-slate-300">
              <li><a className="hover:text-white" href="#features">Features</a></li>
              <li><a className="hover:text-white" href="#precios">Precios</a></li>
              <li><a className="hover:text-white" href="#faq">FAQ</a></li>
            </ul>
          </nav>
        </div>
      </header>

      <main id="contenido" className="mx-auto max-w-5xl px-4 py-10">
        {children}
      </main>

      <footer className="border-t border-white/10">
        <div className="mx-auto max-w-5xl px-4 py-6">
          <small className="text-slate-400">© 2026</small>
        </div>
      </footer>
    </div>
  );
}

Decisión práctica: Tailwind te deja iterar rápido cuando cae el “ajústale tantito” por Slack. Pero no reemplaza la semántica. Puedes tener clases perfectas sobre una estructura equivocada y el sitio seguirá siendo una bronca para mantener.

HTML: la estructura del mundo web (sin humo) - visual explicativa 1
Visual de apoyo: Qué te vas a llevar

Screenshots sugeridos

  1. DevTools (Elements) mostrando una estructura semántica: header/nav/main/section/footer.
  2. Lighthouse / Accessibility con el score y los issues típicos (botones sin nombre, headings desordenados).
  3. Vista móvil con el “skip link” activado (focus visible al tab).
  4. React component tree (React DevTools) enseñando AppLayout y una página dentro de main.

Errores comunes (y cómo salir sin llorar)

Error 1: Todo es <div> porque “React ya se encarga”

Síntoma: CSS frágil, navegación confusa, Lighthouse te regaña.

Arreglo: cambia contenedores por roles reales:

  • div principal → <main>
  • wrapper de navegación → <nav>
  • tarjetas repetibles → <article>

Error 2: Usar <a> como botón (o al revés)

Síntoma: accesibilidad rara, eventos duplicados, historial roto.

Arreglo:

  • Si navega, <a href="...">.
  • Si ejecuta acción, <button type="button">.

Error 3: Headings por estilo

Síntoma: h1 en cada card, h4 arriba de h2, SEO y accesibilidad confundidos.

Arreglo: jerarquía primero, estilo después (Tailwind/CSS).

Error 4: Inputs sin label porque “se ve más clean”

Síntoma: área clickeable mínima, screen readers perdidos, forms incómodos en mobile.

Arreglo: label siempre. Si no lo quieres visible, escóndelo de forma accesible (sr-only).

Error 5: alt="imagen" o alt inexistente

Síntoma: contenido inaccesible, audit findings.

Arreglo: alt descriptivo o vacío si es decorativa.

HTML: la estructura del mundo web (sin humo) - visual explicativa 2
Visual de apoyo: Contexto real (el jale no viene “perfecto”)

Checklist final (para tu próximo PR)

  • Hay <!doctype html> y lang="es-MX".
  • La página tiene un <h1> y headings en orden.
  • Hay <header>, <nav aria-label>, <main id="contenido"> y <footer> cuando aplica.
  • Las acciones usan <button> y la navegación usa <a>.
  • Formularios con label + id/for, type correcto y autocomplete razonable.
  • Imágenes con alt útil (o alt="" si son decorativas).
  • Puedes navegar con teclado sin quedarte atorado (Tab/Shift+Tab) y hay focus visible.

FAQ

1) ¿HTML semántico sí impacta SEO o es puro “nice to have”?

Sí impacta. No es magia, pero ayuda a que crawlers entiendan estructura y reduce ambigüedad (headings, artículos, navegación). De rebote, suele mejorar UX y accesibilidad.

2) ¿Cuántos <main> puede haber?

Uno por documento/vista. Si tienes layouts anidados en React, cuida que solo el layout principal renderice <main>.

3) ¿section o div? ¿cuándo uso section?

section cuando el bloque es una sección temática y tiene heading (o debería tenerlo). Si solo es un wrapper para estilo/layout, div está perfecto.

Si tu página tiene navegación arriba (casi siempre), es una mejora barata y poderosa para teclado y lectores de pantalla. En apps con menús largos se siente como fast travel.

5) En React, ¿por qué me importa el HTML si todo es JSX?

Porque JSX compila a HTML real. Si tu markup está chueco, tu app se porta chueca para el navegador y para usuarios. React no te arregla semántica; solo te da componentes.

Siguiente episodio

De estructura nos vamos a la piel: CSS que no se pelea contigo.

Flex, grid, responsive sin hacks y cómo Tailwind encaja sin convertir tu HTML en sopa.