Parte 5 de 11
Layout y componentes
El layout base con cabecera, navegación responsive y pie de página reutilizables.
La clave de Astro es que puedes reutilizar la estructura. Hice tres piezas: un layout global y dos componentes (navegación y pie). Así cada página solo escribe su contenido.
El layout Base.astro
Todo lo común de la página: <head> con meta, las fuentes, un enlace para saltar al contenido y el hueco donde cada página inserta lo suyo (<slot />):
---
import Nav from '../components/Nav.astro';
import Footer from '../components/Footer.astro';
const siteName = import.meta.env.SITE_NAME ?? 'Portfolio';
---
<!doctype html>
<html lang="es">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{Astro.props.title ?? siteName}</title>
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
</head>
<body>
<a class="skip-link" href="#main">Saltar al contenido</a>
<Nav />
<main id="main">
<slot />
</main>
<Footer />
</body>
</html>
La navegación Nav.astro
Un header fijo (sticky), con el nombre como marca y los enlaces. En móvil se convierte en un botón hamburguesa con un poco de JavaScript vanilla para abrir/cerrar el menú:
<header class="site-header">
<div class="container nav-wrap">
<a class="brand" href="/">{siteName}</a>
<button class="nav-toggle" aria-expanded="false" aria-controls="nav-menu" data-nav-toggle>
<span class="visually-hidden">Abrir menú</span>
<span class="nav-toggle-line"></span>
<span class="nav-toggle-line"></span>
<span class="nav-toggle-line"></span>
</button>
<nav id="nav-menu" aria-label="Principal">
<ul>
<li><a href="/">Inicio</a></li>
<li><a href="/sobre-mi">Sobre mí</a></li>
<li><a href="/proyectos">Proyectos</a></li>
</ul>
</nav>
</div>
</header>
<script>
const toggle = document.querySelector('[data-nav-toggle]');
const menu = document.querySelector('#nav-menu');
toggle?.addEventListener('click', () => {
const open = toggle.getAttribute('aria-expanded') === 'true';
toggle.setAttribute('aria-expanded', String(!open));
menu?.classList.toggle('open');
});
</script>
Con aria-expanded y aria-controls el botón es comprensible para lectores de pantalla. El CSS con @media (max-width: 720px) oculta el menú y muestra el botón hamburguesa.
El pie Footer.astro
El pie reutiliza los enlaces de redes desde variables de entorno (más sobre esto en la parte 6):
---
const siteName = import.meta.env.SITE_NAME ?? 'Portfolio';
const githubUrl = import.meta.env.SITE_GITHUB_URL ?? '';
const linkedinUrl = import.meta.env.SITE_LINKEDIN_URL ?? '';
---
<footer>
<div class="container">
<p>© {new Date().getFullYear()} {siteName}</p>
<ul>
<li><a href={githubUrl}>GitHub</a></li>
<li><a href={linkedinUrl}>LinkedIn</a></li>
</ul>
</div>
</footer>
¿Por qué no duplicar el código en cada página?
Porque entonces, para cambiar el menú, tendrías que tocarlo en cuatro archivos. Con componentes, lo cambias una vez y todas las páginas se regeneran. Ese es el mayor ahorro de un SSG como Astro.
En la siguiente parte, el tema que más me preguntaron: cómo tener datos personales en la web sin que aparezcan en el repositorio público.