astro-layouts-plantillas

Layouts y Plantillas en Astro

  • 5 min

Ahora que hemos visto componentes, podríamos usarlos directamente para hacer las páginas que componen nuestra web.

Por ejemplo, si nuestra web tuviera dos páginas, principal y contacto, podríamos crear un componente index.astro y contacto.astro.

En la siguiente entrada veremos como direccionar (routear) cada página a su componente, y como hacerlo mejor si tuvieramos muchas muchas páginas.

Pero de momento, vamos por aquí. Una página, un componente.

Pero tendríamos un problema: estamos repitiendo código. En ambos archivos tenemos el <!DOCTYPE html>, el <html>, el <head>, los <meta> tags, el body.

Si mañana queremos cambiar el título de la web, añadir una fuente de Google Fonts o instalar Google Analytics, ¿no vas a ir archivo por archivo editando el <head>?

Para solucionar esto, Astro utiliza los Layouts (plantillas).

¿Qué es un Layout en Astro?

Un Layout en Astro no es más que un componente normal y corriente. No existe un tipo de archivo especial.

Es simplemente un archivo .astro que utiliza la etiqueta <slot /> (que vimos en la lección anterior) para envolver el contenido de una página.

Por simple convención, estos componentes los guardamos en la carpeta src/layouts/. Y ya está, no tiene más (parece una chorrada pero son útiles).

Creando nuestro Layout base

Vamos a verlo con un ejemplo. Creemos el archivo Layout.astro. Este archivo será el “esqueleto” o “wrapper” de todas las páginas de nuestro sitio.

src/layouts/Layout.astro
---
interface Props {
  title: string;
  description?: string;
}

const { title, description = "Bienvenido a mi web hecha con Astro" } = Astro.props;
---

<!doctype html>
<html lang="es">
  <head>
    <meta charset="UTF-8" />
    <meta name="description" content={description} />
    <meta name="viewport" content="width=device-width" />
    <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
    <meta name="generator" content={Astro.generator} />
    <title>{title}</title>
  </head>
  <body>
    <slot />
  </body>
</html>

<style is:global>
  /* Estilos globales para toda la web */
  html {
    font-family: system-ui, sans-serif;
    background: #13151a;
    color: white;
  }
  
  body {
    margin: 0;
    padding: 0;
  }
</style>
Copied!

Analicemos qué hemos hecho:

  1. Definimos Props: El layout acepta un title y una description para que cada página tenga su propio SEO.
  2. Estructura HTML: Hemos centralizado todo el boilerplate HTML.
  3. El <slot />: Esta es la clave. Todo lo que escribamos dentro de nuestras páginas se inyectará justo donde hemos puesto esta etiqueta, dentro del <body>.
  4. Estilos globales: Hemos usado <style is:global>. Esto aplica CSS a toda la web (perfecto para resets o fuentes base).

Usando el Layout en una página

Ahora, veamos como usaríamos el concepto de layout para hacer nuestra página de inicio index.astro. Vamos a eliminar todo el HTML repetitivo y contenerlo en un Layout.

src/pages/index.astro
---

import Layout from '../layouts/Layout.astro';
import Boton from '../components/Boton.astro';
---

<Layout title="Inicio | Mi Web Astro">
  
  <main>
    <h1>Bienvenido al futuro</h1>
    <p>Esta página está envuelta en un Layout.</p>
    
    <Boton texto="Saber más" />
  </main>

</Layout>
Copied!

¡Fíjate qué limpieza! Nuestro archivo index.astro ahora solo se preocupa del contenido, no de la configuración del documento.

Si vamos a contacto.astro, haremos lo mismo:

src/pages/contacto.astro
---
import Layout from '../layouts/Layout.astro';
---

<Layout title="Contacto" description="Ponte en contacto con nosotros">
  <h1>Formulario de contacto</h1>
</Layout>
Copied!

Un Layout no suele ser solo HTML vacío. Normalmente queremos que todas las páginas tengan el mismo Menú de Navegación (Header) y el mismo Pie de Página (Footer).

Lo ideal es crear componentes para estas piezas e integrarlos en el Layout.

Supongamos que tenemos src/components/Header.astro y src/components/Footer.astro. Actualizamos nuestro Layout:

src/layouts/Layout.astro
---
import Header from '../components/Header.astro';
import Footer from '../components/Footer.astro';

interface Props {
  title: string;
}
const { title } = Astro.props;
---

<!doctype html>
<html lang="es">
  <head>
    <title>{title}</title>
    </head>
  <body>
    
    <Header />
    
    <main class="contenido-principal">
      <slot />
    </main>

    <Footer />

  </body>
</html>
Copied!

Ahora, con un solo cambio en Header.astro, se actualiza el menú en las 500 páginas de tu sitio web.

Layouts para Markdown

Astro tiene una característica genial para los que escriben mucho contenido en Markdown (como esta página que estás leyendo).

Podemos especificar qué Layout debe usar un archivo .md directamente en su frontmatter (el de Markdown, no el de Astro).

src/pages/blog/mi-artículo.md
---

layout: ../../layouts/BlogLayout.astro
title: "Mi primer post"
author: "Luis Llamas"
---

Aquí escribo en Markdown normal. Astro cogerá este contenido
y lo inyectará en el <slot /> del BlogLayout.
Copied!

El componente BlogLayout.astro recibirá automáticamente todas las variables del frontmatter (title, author, etc.) dentro de la prop frontmatter.

---
// src/layouts/BlogLayout.astro
const { frontmatter } = Astro.props;
---

<html lang="es">
  <h1>{frontmatter.title}</h1>
  <p>Escrito por: {frontmatter.author}</p>
  
  <article>
    <slot /> </article>
</html>
Copied!

Anidamiento de Layouts

Una técnica un poquito más avanzada es que también podemos anidar layouts. Es decir, usar un Layout como plantilla para otro Layout

¿Para qué? Imagina que tienes el LayoutBase.astro (con el HTML y SEO). Pero para unas páginas quieres un diseño con una barra lateral (Sidebar), y para el resto de la web no.

Puedes crear un SidebarLayout.astro que use el LayoutBase.astro:

src/layouts/SidebarLayout.astro
---
import LayoutBase from './LayoutBase.astro';
const { title } = Astro.props;
---

<LayoutBase title={title}>
  <div class="pantalla-dividida">
    <aside>Soy la barra lateral del blog</aside>
    <main>
      <slot />
    </main>
  </div>
</LayoutBase>
Copied!

Así tendrías

  • Un LayoutBase con la estructura mínima y común a toda la web
  • Un Layout... por cada tipo de página que tengas (con sidebar, con dos sidebar, etc)