Proyecto: tu primera web en HTML
En esta lección
Ha llegado el momento de juntar todo lo que has aprendido en el curso y construir una web completa de varias páginas, como la que podrías entregar en clase o enseñar en tu portfolio. Vas a hacer la web de Club Vertical, un club de escalada ficticio: una portada, una página de actividades y una de contacto con formulario. Verás cómo organizar las carpetas, cómo repetir la navegación en todas las páginas, cómo escribir un <head> completo para buscadores y cómo validar el resultado.
Aquí solo usaremos HTML y una hoja de estilos mínima. El diseño lo aprenderás en el curso de CSS, en el proyecto de maquetación.
Paso 1: planificar antes de escribir
Antes de abrir el editor, responde a tres preguntas:
- ¿Qué páginas necesito? Inicio, Actividades y Contacto.
- ¿Qué contenido va en cada una? Haz una lista a mano o en papel.
- ¿Qué se repite en todas? La cabecera con el menú y el pie de página.
Después, crea la estructura de carpetas:
club-vertical/
├── index.html
├── actividades.html
├── contacto.html
├── gracias.html
├── css/
│ └── estilos.css
└── img/
├── favicon.svg
├── portada.jpg
└── logo.svg
Algunas normas para los nombres de archivo:
- Todo en minúsculas, sin espacios, sin tildes ni eñes:
actividades.html, noActividades Club.html. - Separa palabras con guiones:
curso-iniciacion.html. - La portada se llama siempre
index.html: es el archivo que abre el servidor cuando alguien entra en la carpeta.
Como todas las páginas están en la misma carpeta, los enlaces entre ellas son simples: href="contacto.html". Si tienes dudas, repasa rutas de archivos.
Paso 2: la portada, index.html
Empieza por la página principal. Este es el código completo:
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Club Vertical · Club de escalada en Burgos</title>
<meta name="description" content="Club de escalada en Burgos con rocódromo propio, cursos de iniciación y salidas a roca cada mes. Hazte socio y escala con nosotros.">
<link rel="canonical" href="https://clubvertical.example/">
<link rel="icon" href="img/favicon.svg" type="image/svg+xml">
<link rel="stylesheet" href="css/estilos.css">
<meta property="og:title" content="Club Vertical · Escalada en Burgos">
<meta property="og:description" content="Rocódromo, cursos y salidas a roca.">
<meta property="og:image" content="https://clubvertical.example/img/portada.jpg">
<meta property="og:type" content="website">
</head>
<body>
<a class="saltar" href="#contenido">Saltar al contenido</a>
<header>
<a href="index.html"><img src="img/logo.svg" alt="Club Vertical, ir al inicio" width="160" height="40"></a>
<nav aria-label="Principal">
<ul>
<li><a href="index.html" aria-current="page">Inicio</a></li>
<li><a href="actividades.html">Actividades</a></li>
<li><a href="contacto.html">Contacto</a></li>
</ul>
</nav>
</header>
<main id="contenido">
<section>
<h1>Escala con nosotros en Burgos</h1>
<p>Somos un club sin ánimo de lucro con rocódromo propio y salidas a roca cada mes.</p>
<img src="img/portada.jpg" alt="Una socia escala una pared de roca caliza al atardecer" width="1200" height="600">
<p><a href="actividades.html#iniciacion">Ver cursos de iniciación</a></p>
</section>
<section aria-labelledby="t-proximas">
<h2 id="t-proximas">Próximas salidas</h2>
<article>
<h3>Escalada en La Pedriza</h3>
<p><time datetime="2026-10-18">18 de octubre</time> · Nivel medio</p>
</article>
<article>
<h3>Bautismo de roca en Ojo Guareña</h3>
<p><time datetime="2026-11-08">8 de noviembre</time> · Iniciación</p>
</article>
</section>
<section aria-labelledby="t-cifras">
<h2 id="t-cifras">El club en cifras</h2>
<ul>
<li>210 socios y socias</li>
<li>120 vías en el rocódromo</li>
<li>12 salidas al año</li>
</ul>
</section>
</main>
<footer>
<address>
Calle del Pino 4, 09001 Burgos ·
<a href="mailto:hola@clubvertical.example">hola@clubvertical.example</a> ·
<a href="tel:+34947000000">947 000 000</a>
</address>
<p>© 2026 Club Vertical</p>
</footer>
</body>
</html>
Fíjate en las decisiones importantes:
- Un solo
<h1>con el tema de la página, y<h2>para cada sección. - Landmarks:
<header>,<nav>,<main>y<footer>. Así un lector de pantalla puede saltar al contenido. aria-current="page"marca en el menú la página en la que estás.- Cada salida es un
<article>, porque tiene sentido por sí sola, y la fecha va en<time>con un formato que entienden las máquinas. - Las imágenes llevan
alt,widthyheight.
Paso 3: un <head> completo
El <head> no se ve, pero decide cómo aparece tu web en Google y en las redes. Repasa cada línea:
| Línea | Para qué sirve |
|---|---|
charset="utf-8" | Tildes y eñes correctas |
viewport | Que se vea bien en el móvil |
<title> | Pestaña del navegador y título en Google. Distinto en cada página |
description | El resumen que suele mostrar Google. Unos 150 caracteres, distinto en cada página |
canonical | La dirección oficial de la página, para evitar duplicados |
icon | El icono de la pestaña (favicon) |
stylesheet | Enlaza el CSS |
og:* | Título, texto e imagen al compartir en redes |
Tienes cada etiqueta explicada en la cabecera de un documento.
Paso 4: la página de actividades
Copia index.html, renómbralo a actividades.html y cambia lo que no se repite: el <title>, la description, el canonical, el aria-current del menú y el contenido de <main>. La cabecera y el pie quedan igual. Para no alargar, en esta página y las siguientes el <head> omite las etiquetas og:; añádelas si quieres que se compartan bien en redes. Así queda el archivo completo:
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Actividades y cursos · Club Vertical</title>
<meta name="description" content="Cursos de iniciación y perfeccionamiento, rocódromo libre y salidas a roca. Consulta horarios y precios de las actividades del club.">
<link rel="canonical" href="https://clubvertical.example/actividades.html">
<link rel="icon" href="img/favicon.svg" type="image/svg+xml">
<link rel="stylesheet" href="css/estilos.css">
</head>
<body>
<a class="saltar" href="#contenido">Saltar al contenido</a>
<header>
<a href="index.html"><img src="img/logo.svg" alt="Club Vertical, ir al inicio" width="160" height="40"></a>
<nav aria-label="Principal">
<ul>
<li><a href="index.html">Inicio</a></li>
<li><a href="actividades.html" aria-current="page">Actividades</a></li>
<li><a href="contacto.html">Contacto</a></li>
</ul>
</nav>
</header>
<main id="contenido">
<h1>Actividades</h1>
<section id="iniciacion">
<h2>Curso de iniciación</h2>
<p>Ocho sesiones para aprender a asegurar, nudos básicos y técnica de pies.</p>
<details>
<summary>¿Qué incluye?</summary>
<ul>
<li>Préstamo de arnés y pies de gato</li>
<li>Seguro de actividad</li>
</ul>
</details>
</section>
<section>
<h2>Horarios y precios</h2>
<table>
<caption>Tarifas de la temporada 2026-2027</caption>
<thead>
<tr><th scope="col">Actividad</th><th scope="col">Horario</th><th scope="col">Precio</th></tr>
</thead>
<tbody>
<tr><th scope="row">Iniciación</th><td>Martes y jueves, 18:00</td><td>90 €</td></tr>
<tr><th scope="row">Perfeccionamiento</th><td>Lunes y miércoles, 19:30</td><td>110 €</td></tr>
<tr><th scope="row">Rocódromo libre</th><td>Todos los días, 10:00-22:00</td><td>35 €/mes</td></tr>
</tbody>
</table>
</section>
</main>
<footer>
<address>
Calle del Pino 4, 09001 Burgos ·
<a href="mailto:hola@clubvertical.example">hola@clubvertical.example</a> ·
<a href="tel:+34947000000">947 000 000</a>
</address>
<p>© 2026 Club Vertical</p>
</footer>
</body>
</html>
El enlace de la portada actividades.html#iniciacion lleva directamente a la sección con id="iniciacion".
Consejo: repetir la cabecera en cada archivo es incómodo: si añades una página, tienes que tocar el menú en todas. En proyectos reales esto se resuelve con plantillas (Astro, PHP, un generador de sitios…). Para una web de tres páginas, copiar y pegar es aceptable.
Paso 5: la página de contacto
contacto.html mantiene la misma cabecera y pie. Este es el archivo completo:
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Contacto · Club Vertical</title>
<meta name="description" content="Escribe al Club Vertical para resolver tus dudas sobre cursos de escalada, cuotas de socio o salidas a roca. Te respondemos en 48 horas.">
<link rel="canonical" href="https://clubvertical.example/contacto.html">
<link rel="icon" href="img/favicon.svg" type="image/svg+xml">
<link rel="stylesheet" href="css/estilos.css">
</head>
<body>
<a class="saltar" href="#contenido">Saltar al contenido</a>
<header>
<a href="index.html"><img src="img/logo.svg" alt="Club Vertical, ir al inicio" width="160" height="40"></a>
<nav aria-label="Principal">
<ul>
<li><a href="index.html">Inicio</a></li>
<li><a href="actividades.html">Actividades</a></li>
<li><a href="contacto.html" aria-current="page">Contacto</a></li>
</ul>
</nav>
</header>
<main id="contenido">
<h1>Contacto</h1>
<p>¿Tienes dudas sobre los cursos? Escríbenos y te respondemos en 48 horas.</p>
<form action="gracias.html" method="get">
<p>
<label for="nombre">Nombre</label>
<input type="text" id="nombre" name="nombre" autocomplete="name" required>
</p>
<p>
<label for="email">Correo electrónico</label>
<input type="email" id="email" name="email" autocomplete="email" required>
</p>
<fieldset>
<legend>¿Qué te interesa?</legend>
<label><input type="radio" name="interes" value="iniciacion" checked> Curso de iniciación</label>
<label><input type="radio" name="interes" value="socio"> Hacerme socio</label>
<label><input type="radio" name="interes" value="otro"> Otra cosa</label>
</fieldset>
<p>
<label for="mensaje">Mensaje</label>
<textarea id="mensaje" name="mensaje" rows="5" minlength="10" required></textarea>
</p>
<p>
<label><input type="checkbox" name="privacidad" required> Acepto la política de privacidad</label>
</p>
<button type="submit">Enviar mensaje</button>
</form>
</main>
<footer>
<address>
Calle del Pino 4, 09001 Burgos ·
<a href="mailto:hola@clubvertical.example">hola@clubvertical.example</a> ·
<a href="tel:+34947000000">947 000 000</a>
</address>
<p>© 2026 Club Vertical</p>
</footer>
</body>
</html>
Cada campo tiene su <label>, un name y la validación nativa (required, type="email", minlength). Los botones de opción van agrupados en un <fieldset> con su <legend>.
Una web solo con HTML no puede recibir mensajes: alguien tiene que procesarlos en un servidor. Aquí el formulario simplemente lleva a gracias.html. Como no aporta nada en los buscadores, lleva noindex para que Google no la muestre:
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Mensaje enviado · Club Vertical</title>
<meta name="robots" content="noindex">
<link rel="icon" href="img/favicon.svg" type="image/svg+xml">
<link rel="stylesheet" href="css/estilos.css">
</head>
<body>
<a class="saltar" href="#contenido">Saltar al contenido</a>
<header>
<a href="index.html"><img src="img/logo.svg" alt="Club Vertical, ir al inicio" width="160" height="40"></a>
<nav aria-label="Principal">
<ul>
<li><a href="index.html">Inicio</a></li>
<li><a href="actividades.html">Actividades</a></li>
<li><a href="contacto.html">Contacto</a></li>
</ul>
</nav>
</header>
<main id="contenido">
<h1>Gracias por escribirnos</h1>
<p>Hemos recibido tu mensaje. Te responderemos en 48 horas.</p>
<p><a href="index.html">Volver a la página de inicio</a></p>
</main>
<footer>
<address>
Calle del Pino 4, 09001 Burgos ·
<a href="mailto:hola@clubvertical.example">hola@clubvertical.example</a> ·
<a href="tel:+34947000000">947 000 000</a>
</address>
<p>© 2026 Club Vertical</p>
</footer>
</body>
</html>
Para que el formulario funcione de verdad necesitarás un servicio externo de formularios o tu propio servidor, como el que aprenderás a hacer con Express.
Paso 6: una hoja de estilos mínima
Las cuatro páginas enlazan css/estilos.css. Con muy poco CSS la web ya es legible y el enlace de salto queda oculto hasta que recibe el foco:
body { font-family: system-ui, sans-serif; line-height: 1.5; margin: 0; color: #1f2937; }
header, main, footer { padding: 16px; max-width: 60rem; margin: 0 auto; }
nav ul { list-style: none; padding: 0; display: flex; gap: 16px; }
img { max-width: 100%; height: auto; }
.saltar { position: absolute; left: -9999px; }
.saltar:focus { left: 8px; top: 8px; background: #fff; padding: 8px; }
La línea img { max-width: 100%; height: auto; } evita que la foto de portada, de 1200 píxeles, se salga de la pantalla en el móvil.
Paso 7: validar y probar
Con las páginas escritas, toca revisarlas:
- Validador del W3C (validator.w3.org): sube cada archivo y corrige todos los errores. Te lo explicamos en buenas prácticas.
- Prueba los enlaces. Pulsa todos los del menú en las tres páginas y el de
#iniciacion. - Recorre la web con el teclado. Tab desde el principio: debe aparecer el enlace de salto, luego el menú y luego el contenido.
- Lighthouse. Analiza la portada con las categorías Accessibility y SEO.
- Prueba en el móvil con el modo de dispositivo de las herramientas de desarrollo.
Errores frecuentes
- Mismo
<title>en todas las páginas. Google no sabe cuál mostrar y la persona no distingue las pestañas. - Rutas con mayúsculas o espacios. En tu ordenador funciona, en el servidor (que distingue mayúsculas) no.
- Olvidar cambiar
aria-currental copiar la cabecera en otra página. - Formularios sin
name: los datos no se envían. - Maquetar con tablas. La tabla de precios está bien porque son datos; la estructura de la página, no.
- Dejar la validación para el final. Valida cada página nada más terminarla: los errores son más fáciles de encontrar.
Lista de comprobación final
Antes de dar la web por terminada, repasa esta lista en cada página:
-
<!DOCTYPE html>y<html lang="es"> -
charset,viewport,<title>ydescriptionpropios de la página - Un único
<h1>y encabezados sin saltos de nivel -
<header>,<nav>,<main>y<footer>presentes - Menú idéntico en todas las páginas, con
aria-currenten la actual - Todas las imágenes con
alt,widthyheight - Enlaces con texto descriptivo y rutas relativas correctas
- Formularios con
<label>,namey validación - Tablas con
<caption>y<th>conscope - Nombres de archivo en minúsculas y sin espacios
- Cero errores en el validador del W3C
- Se puede usar entera con el teclado
Si cumples toda la lista, tienes una web sólida, accesible y lista para que le pongas estilo. El siguiente paso es darle diseño en el curso de CSS, empezando por la introducción a CSS.
Pruébalo tú
Cambia el código y pulsa Ejecutar (o Ctrl + Enter).
Pon a prueba lo que has aprendido
¿Te ha quedado claro? Márcala y verás tu progreso en el explorador.