Saltar al contenido
proyecto-blog.html · devschool

Proyecto: un blog con HTML semántico

Lección 37 de 39 · 13 min de lectura · Actualizado el

En esta lección
  1. Paso 1: planificar
  2. Paso 2: el <head> con metadatos
  3. Paso 3: la cabecera y la navegación
  4. Paso 4: la lista de entradas (página de inicio)
  5. Paso 5: la entrada completa
  6. Paso 6: los comentarios y el formulario
  7. Paso 7: el pie de página
  8. Paso 8: datos estructurados para buscadores
  9. El código final
  10. Paso 9: comprobar el resultado
  11. Ideas para ampliarlo
  12. Errores frecuentes
  13. Resumen

Un blog es el mejor ejercicio para practicar HTML semántico, porque casi todas las etiquetas del curso tienen aquí un sitio natural: cabecera, navegación, artículos, imágenes con pie, citas, notas laterales, fechas, un formulario y un pie de página. En este proyecto vas a construir paso a paso Cuaderno de Monte, un blog ficticio de senderismo, con dos páginas: la lista de entradas y una entrada completa con comentarios. Al final tendrás el código completo y una lista de comprobación.

No hace falta CSS para que la estructura sea correcta; al final añadiremos unos estilos mínimos solo para que se vea decente. Si necesitas repasar alguna etiqueta, tienes HTML semántico y el head y los metadatos.

Paso 1: planificar

Antes de escribir, dibuja en papel qué lleva cada página. Es una costumbre barata que evita rehacer el HTML después.

Página de inicio (index.html)         Entrada (articulo.html)
- cabecera con nombre y menú          - cabecera con nombre y menú
- lista de entradas recientes         - artículo
    - cada entrada: título, fecha,        - título, autor, fecha
      resumen, enlace                     - imagen con pie
- barra lateral con categorías            - texto con subtítulos y cita
- pie                                     - nota lateral
                                      - comentarios + formulario
                                      - pie

Para cada bloque pregúntate qué es, no cómo se verá: una lista de entradas es una lista de artículos independientes; la barra lateral es contenido relacionado pero prescindible. Eso te dice qué etiqueta usar.

La estructura de carpetas es sencilla:

cuaderno-de-monte/
  index.html
  articulo.html
  css/estilos.css
  img/valle.jpg

Paso 2: el <head> con metadatos

El <head> es lo primero que leen los buscadores y las redes sociales. Este es el de la página de la entrada:

<!DOCTYPE html>
<html lang="es">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Mi primera noche en un refugio de montaña | Cuaderno de Monte</title>
  <meta name="description" content="Qué llevar, qué sobra y qué aprendí en mi primera noche en un refugio de montaña. Consejos prácticos para principiantes.">
  <link rel="canonical" href="https://cuadernodemonte.example/primera-noche-en-refugio/">

  <!-- Para redes sociales (Open Graph) -->
  <meta property="og:type" content="article">
  <meta property="og:title" content="Mi primera noche en un refugio de montaña">
  <meta property="og:description" content="Qué llevar, qué sobra y qué aprendí en mi primera noche en un refugio.">
  <meta property="og:image" content="https://cuadernodemonte.example/img/valle-1200x630.jpg">
  <meta property="og:url" content="https://cuadernodemonte.example/primera-noche-en-refugio/">
  <meta name="twitter:card" content="summary_large_image">

  <link rel="stylesheet" href="css/estilos.css">
</head>

Los puntos importantes:

  • lang="es" en <html>, para lectores de pantalla y traductores.
  • Un <title> distinto en cada página y una description de unos 150 caracteres. Son el título y el texto que Google muestra en sus resultados.
  • canonical indica la dirección oficial de la página, para que no se indexen duplicados.
  • Las etiquetas og: controlan cómo se ve el enlace al compartirlo. La imagen suele medir 1200 x 630 píxeles. Más detalle en SEO en HTML.

Paso 3: la cabecera y la navegación

En todas las páginas se repite el mismo bloque:

<body>
  <header>
    <p class="marca"><a href="index.html">Cuaderno de Monte</a></p>
    <nav aria-label="Principal">
      <ul>
        <li><a href="index.html" aria-current="page">Blog</a></li>
        <li><a href="rutas.html">Rutas</a></li>
        <li><a href="sobre-mi.html">Sobre mí</a></li>
      </ul>
    </nav>
  </header>

Detalles que marcan la diferencia:

  • El nombre del blog va en un <p> y no en un <h1>: en cada página, el <h1> debe ser el título de ese contenido.
  • La navegación es una lista (<ul>) dentro de <nav>, con aria-label para distinguirla de otras navegaciones.
  • aria-current="page" marca el enlace de la página actual para los lectores de pantalla y te permite darle estilo.

Paso 4: la lista de entradas (página de inicio)

Cada entrada de la lista es un <article>: un trozo de contenido que tendría sentido por sí solo, por ejemplo en un lector de noticias.

<main>
  <h1>Últimas entradas</h1>

  <article>
    <h2><a href="articulo.html">Mi primera noche en un refugio de montaña</a></h2>
    <p><time datetime="2026-09-14">14 de septiembre de 2026</time> · 5 min de lectura</p>
    <p>Qué llevar, qué sobra y lo que aprendí al dormir a 2.100 metros.</p>
    <p><a href="articulo.html">Leer la entrada completa</a></p>
  </article>

  <article>
    <h2><a href="#">Cinco rutas fáciles para empezar en otoño</a></h2>
    <p><time datetime="2026-09-02">2 de septiembre de 2026</time> · 4 min de lectura</p>
    <p>Senderos cortos, bien señalizados y con buenas vistas.</p>
    <p><a href="#">Leer la entrada completa</a></p>
  </article>
</main>

Observa:

  • Un solo <h1> por página, y los títulos de las entradas son <h2>.
  • El título es el propio enlace: así la persona que navega con lector de pantalla oye una lista de títulos claros.
  • La fecha va dentro de <time>. El texto es lo que lee la persona (“14 de septiembre de 2026”) y el atributo datetime es el valor que entienden las máquinas, siempre en formato AAAA-MM-DD.
  • El texto del último enlace, “Leer la entrada completa”, es descriptivo. Evita enlaces que solo digan “Pincha aquí”.

Si quieres una barra lateral con categorías, va fuera de <main> o dentro de él como <aside>, con su propio título y una lista de enlaces.

Paso 5: la entrada completa

Esta es la parte central del proyecto. Todo el contenido de la entrada va dentro de un <article>, y su cabecera lleva el título, el autor y la fecha:

<main>
  <article>
    <header>
      <h1>Mi primera noche en un refugio de montaña</h1>
      <p>
        Por <a href="sobre-mi.html">Marta Ibáñez</a> ·
        <time datetime="2026-09-14">14 de septiembre de 2026</time> ·
        5 min de lectura
      </p>
    </header>

Un <header> dentro de un <article> es la cabecera de esa entrada, no la de la página. Es normal tener varios <header> en un documento.

La imagen con <figure>

    <figure>
      <img src="img/valle.jpg" width="800" height="400"
           alt="Un valle con montañas al atardecer y un sendero en primer plano">
      <figcaption>El valle desde el refugio, poco antes de cenar.</figcaption>
    </figure>

<figure> agrupa la imagen con su pie <figcaption>. El alt describe lo que se ve, para quien no puede verla; el figcaption es el pie visible para todos, así que no repitas el mismo texto. Los atributos width y height reservan el hueco y evitan que la página “salte” al cargar la imagen. Si la tienes en varios tamaños, mira imágenes responsive.

El texto con subtítulos

    <p>Llegué a las seis de la tarde con las piernas cargadas y una mochila demasiado pesada.</p>

    <h2>Lo que metí en la mochila</h2>
    <p>Aprendí rápido qué sobraba: el segundo par de botas y casi toda la comida.</p>

Los subtítulos son <h2>, y si hay subapartados, <h3>. No saltes niveles (de <h2> a <h4>) y no elijas un nivel por su tamaño: el tamaño se cambia con CSS.

La cita con <blockquote>

    <blockquote cite="https://cuadernodemonte.example/entrevista-guarda/">
      <p>En la montaña, lo que no llevas no pesa.</p>
      <footer>— El guarda del refugio</footer>
    </blockquote>

<blockquote> es para citas largas de otra persona. El atributo cite guarda la URL de la fuente (no se ve, pero la usan las máquinas) y el autor visible va aparte, en un <footer> o en un <cite>. Para una cita corta dentro de una frase, usa <q>.

La nota lateral con <aside>

    <aside>
      <h2>Para saber más</h2>
      <p>Consulta la <a href="material.html">lista de material imprescindible</a> antes de salir.</p>
    </aside>
  </article>

Un <aside> contiene algo relacionado con el contenido, pero prescindible: si lo quitas, el artículo se entiende igual. Una pregunta útil para decidir: “¿se podría mover a un cuadro al margen?”.

Paso 6: los comentarios y el formulario

Los comentarios son una sección (<section>) con su propio título, porque es un bloque temático dentro de la página. Cada comentario es un <article>, ya que es contenido independiente escrito por otra persona:

  <section aria-labelledby="comentarios">
    <h2 id="comentarios">Comentarios (1)</h2>

    <article class="comentario">
      <h3>Luis</h3>
      <p><time datetime="2026-09-15T09:30">15 de septiembre, 9:30</time></p>
      <p>Yo también llevé de más la primera vez.</p>
    </article>

    <form action="/comentarios" method="post">
      <h3>Deja tu comentario</h3>
      <p>
        <label for="nombre">Nombre</label><br>
        <input id="nombre" name="nombre" autocomplete="nickname" required>
      </p>
      <p>
        <label for="texto">Comentario</label><br>
        <textarea id="texto" name="texto" rows="4" maxlength="1000" required></textarea>
      </p>
      <p><button type="submit">Publicar</button></p>
    </form>
  </section>
</main>

Lo esencial del formulario:

  • Cada campo tiene su <label> enlazado con for e id: así se puede pulsar la etiqueta para enfocar el campo y los lectores de pantalla la anuncian.
  • required y maxlength hacen una primera validación sin JavaScript; el servidor tiene que repetirla siempre. Tienes más en validar formularios.
  • autocomplete ayuda al navegador a rellenar los datos.
  • aria-labelledby en la <section> la nombra con el texto del <h2>, de modo que sea un punto de referencia para quien navega con lector de pantalla.

Paso 7: el pie de página

<footer>
  <p>© 2026 Cuaderno de Monte · <a href="privacidad.html">Política de privacidad</a></p>
</footer>
</body>
</html>

Un <footer> colgado directamente del <body> es el pie de la página. Suele llevar el copyright, el aviso legal y enlaces secundarios.

Paso 8: datos estructurados para buscadores

Un último extra para que Google entienda que la página es un artículo: un bloque JSON-LD dentro del <head> (explicado en datos estructurados):

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "BlogPosting",
  "headline": "Mi primera noche en un refugio de montaña",
  "datePublished": "2026-09-14",
  "author": { "@type": "Person", "name": "Marta Ibáñez" },
  "image": "https://cuadernodemonte.example/img/valle-1200x630.jpg"
}
</script>

Los datos tienen que coincidir con lo que se ve en la página.

El código final

Esta es la página articulo.html completa, con todo lo anterior junto:

<!DOCTYPE html>
<html lang="es">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Mi primera noche en un refugio de montaña | Cuaderno de Monte</title>
  <meta name="description" content="Qué llevar, qué sobra y qué aprendí en mi primera noche en un refugio de montaña. Consejos prácticos para principiantes.">
  <link rel="canonical" href="https://cuadernodemonte.example/primera-noche-en-refugio/">
  <meta property="og:type" content="article">
  <meta property="og:title" content="Mi primera noche en un refugio de montaña">
  <meta property="og:description" content="Qué llevar, qué sobra y qué aprendí en mi primera noche en un refugio.">
  <meta property="og:image" content="https://cuadernodemonte.example/img/valle-1200x630.jpg">
  <meta property="og:url" content="https://cuadernodemonte.example/primera-noche-en-refugio/">
  <meta name="twitter:card" content="summary_large_image">
  <link rel="stylesheet" href="css/estilos.css">
  <script type="application/ld+json">
  {
    "@context": "https://schema.org",
    "@type": "BlogPosting",
    "headline": "Mi primera noche en un refugio de montaña",
    "datePublished": "2026-09-14",
    "author": { "@type": "Person", "name": "Marta Ibáñez" },
    "image": "https://cuadernodemonte.example/img/valle-1200x630.jpg"
  }
  </script>
</head>
<body>
  <header>
    <p class="marca"><a href="index.html">Cuaderno de Monte</a></p>
    <nav aria-label="Principal">
      <ul>
        <li><a href="index.html" aria-current="page">Blog</a></li>
        <li><a href="rutas.html">Rutas</a></li>
        <li><a href="sobre-mi.html">Sobre mí</a></li>
      </ul>
    </nav>
  </header>

  <main>
    <article>
      <header>
        <h1>Mi primera noche en un refugio de montaña</h1>
        <p>
          Por <a href="sobre-mi.html">Marta Ibáñez</a> ·
          <time datetime="2026-09-14">14 de septiembre de 2026</time> ·
          5 min de lectura
        </p>
      </header>

      <figure>
        <img src="img/valle.jpg" width="800" height="400"
             alt="Un valle con montañas al atardecer y un sendero en primer plano">
        <figcaption>El valle desde el refugio, poco antes de cenar.</figcaption>
      </figure>

      <p>Llegué a las seis de la tarde con las piernas cargadas y una mochila demasiado pesada.</p>

      <h2>Lo que metí en la mochila</h2>
      <p>Aprendí rápido qué sobraba: el segundo par de botas y casi toda la comida.</p>

      <blockquote cite="https://cuadernodemonte.example/entrevista-guarda/">
        <p>En la montaña, lo que no llevas no pesa.</p>
        <footer>— El guarda del refugio</footer>
      </blockquote>

      <aside>
        <h2>Para saber más</h2>
        <p>Consulta la <a href="material.html">lista de material imprescindible</a> antes de salir.</p>
      </aside>
    </article>

    <section aria-labelledby="comentarios">
      <h2 id="comentarios">Comentarios (1)</h2>

      <article class="comentario">
        <h3>Luis</h3>
        <p><time datetime="2026-09-15T09:30">15 de septiembre, 9:30</time></p>
        <p>Yo también llevé de más la primera vez.</p>
      </article>

      <form action="/comentarios" method="post">
        <h3>Deja tu comentario</h3>
        <p>
          <label for="nombre">Nombre</label><br>
          <input id="nombre" name="nombre" autocomplete="nickname" required>
        </p>
        <p>
          <label for="texto">Comentario</label><br>
          <textarea id="texto" name="texto" rows="4" maxlength="1000" required></textarea>
        </p>
        <p><button type="submit">Publicar</button></p>
      </form>
    </section>
  </main>

  <footer>
    <p>© 2026 Cuaderno de Monte · <a href="privacidad.html">Política de privacidad</a></p>
  </footer>
</body>
</html>

Y unos estilos mínimos para css/estilos.css:

body {
  font-family: Georgia, serif;
  line-height: 1.6;
  max-width: 42rem;
  margin: 0 auto;
  padding: 0 16px;
}
nav ul { display: flex; gap: 16px; list-style: none; padding: 0; }
img { max-width: 100%; height: auto; }
blockquote { padding-left: 16px; border-left: 4px solid #2f6f4f; }
aside { background: #f3efe6; padding: 8px 16px; border-radius: 6px; }

Paso 9: comprobar el resultado

  1. Valida el HTML en el validador del W3C (validator.w3.org): no debe dar errores.
  2. Desactiva el CSS (o léelo sin estilos) y comprueba que el orden de lectura tiene sentido.
  3. Navega solo con el teclado (Tab): todos los enlaces y campos deben ser alcanzables, con el foco visible.
  4. Revisa los títulos: un único <h1> y ningún nivel saltado.
  5. Pega la URL en un comprobador de tarjetas de redes sociales para ver cómo se comparte. Para eso la web debe estar publicada: mira publicar tu web.

Ideas para ampliarlo

  • Una página de categorías con una lista de entradas por tema.
  • Paginación con <nav aria-label="Paginación"> y enlaces “Anterior” y “Siguiente”.
  • Un enlace “Saltar al contenido” al principio de la página.
  • Un feed RSS enlazado con <link rel="alternate" type="application/rss+xml">.
  • Estilos en dos columnas con Grid, dejando el <aside> a un lado.

Errores frecuentes

  • Usar <div> para todo. Si algo es un artículo, una cita o una fecha, tiene su etiqueta. Un <div> no dice nada a buscadores ni a lectores de pantalla.
  • Dos <h1> o ninguno. Debe haber uno por página, con el título de lo principal.
  • Elegir un título por su tamaño. El nivel indica la jerarquía; el tamaño es cosa del CSS.
  • Poner la fecha solo como texto. Con <time datetime="..."> las máquinas la entienden.
  • Repetir el mismo <title> y description en todas las páginas. Cada una necesita los suyos.
  • Imágenes sin alt o con alt="imagen". Describe lo que se ve y por qué importa.
  • Usar <section> sin título. Una <section> debe tener un encabezado; si no, probablemente necesitas un <div>.

Resumen

Parte del blogEtiquetaDetalle clave
Cabecera del sitio<header> + <nav>aria-label y aria-current="page"
Contenido principal<main>Uno por página
Entrada del blog<article>Título con <h1> o <h2> según la página
Fecha<time datetime="...">Formato AAAA-MM-DD
Imagen con pie<figure> + <figcaption>alt, width y height
Cita<blockquote cite>Autor aparte
Nota relacionada<aside>Prescindible
Comentarios<section> + <article>Con aria-labelledby
Formulario<form> + <label>required, autocomplete
Redes y buscadores<meta> y JSON-LDdescription, og:, canonical

En la siguiente lección practicarás con otro proyecto: un formulario de inscripción accesible. Y cuando quieras ponerle estilo a tu blog, pasa al curso de CSS.

Pruébalo tú

Cambia el código y pulsa Ejecutar (o Ctrl + Enter).

proyecto-blog.html
Resultado

Pon a prueba lo que has aprendido

[HTML] En la lista de entradas del inicio, ¿qué etiqueta conviene para cada entrada y qué nivel de título?

[HTML] ¿Qué hace el atributo datetime de esta etiqueta?
<time datetime="2026-09-14">14 de septiembre de 2026</time>

[HTML] Una imagen del artículo con su pie visible. ¿Cuál es la estructura correcta?

[HTML] ¿Para qué sirve aria-current="page" en un enlace del menú?
<a href="index.html" aria-current="page">Blog</a>

¿Te ha quedado claro? Márcala y verás tu progreso en el explorador.