Saltar al contenido

Metadatos base: title, description y un componente SEO

El punto de partida del SEO en Astro 7: escribir títulos y descripciones que respeten los límites del buscador, encapsular esos metadatos en un componente reutilizable y tipado, y derivar la URL canónica autorreferente desde Astro.url y Astro.site para que ninguna página salga al mundo sin su carta de presentación.

El título y la descripción: el contrato con el buscador

El elemento <title> es la señal en página más determinante que controlas: alimenta la pestaña del navegador, el enlace azul del resultado de búsqueda y el texto que se copia al compartir. Un buscador lo usa para entender de qué trata la página, así que ha de ser específico, único y cargar la palabra clave importante al principio. Los resultados se truncan por ancho en píxeles, no por número de caracteres, pero como regla de bolsillo un título que ronda los 55 o 60 caracteres rara vez se corta. La convención madura es un patrón título de la página · marca, que da contexto sin gastar el espacio útil en el nombre del sitio.

La <meta name="description"> no es un factor de posicionamiento —el buscador no te sube por escribirla bien— pero sí un factor de clics: es el fragmento que acompaña al título en el resultado y convence, o no, de entrar. Apunta a unos 150 caracteres, resume la promesa real de la página y evita el relleno. Conviene aceptar desde ya una verdad incómoda: el buscador reescribe a menudo ese fragmento con el trozo de tu contenido que mejor casa con la consulta, de modo que tu descripción es una propuesta, no una garantía. Escribirla bien inclina la balanza; no la decide.

Un defecto sorprendentemente común, y fácil de evitar con este enfoque, es el título duplicado: decenas de páginas que comparten el mismo <title> porque nadie se ocupó de diferenciarlas. Para el buscador, títulos idénticos son páginas indistinguibles, y unas acaban canibalizando a las otras por las mismas consultas. Derivar el título de un dato propio de cada página —su encabezado, su nombre en la colección— y componerlo en un solo sitio elimina de raíz la clase entera de ese error, porque la unicidad deja de depender de que alguien se acuerde.

ASTRO
---// El patrón "página · marca" en un solo lugarconst { title } = Astro.props;const tituloCompleto = title ? `${title} · nvim-dios` : 'nvim-dios';---<title>{tituloCompleto}</title>

Un componente <SEO /> como única fuente

En el nivel de layouts ya centralizaste el <head>; aquí damos el paso siguiente: extraer los metadatos a su propio componente <SEO />. La diferencia no es cosmética. Un layout mezcla estructura visual con metadatos; un componente dedicado aísla la lógica de SEO en una pieza que se prueba, se razona y se reutiliza por sí sola, incluso en páginas que no comparten layout. Es el mismo principio de responsabilidad única que aplicas al código: el objeto que sabe de buscadores no debería saber también de barras de navegación.

ASTRO
---// src/components/SEO.astrointerface Props {  title: string;  description: string;  canonical?: string | URL;  noindex?: boolean;}const {  title,  description,  canonical = new URL(Astro.url.pathname, Astro.site),  noindex = false,} = Astro.props;const tituloCompleto = `${title} · nvim-dios`;---<title>{tituloCompleto}</title><meta name="description" content={description} /><link rel="canonical" href={canonical.toString()} />{noindex && <meta name="robots" content="noindex, nofollow" />}

La interfaz Props convierte el contrato en algo que la máquina verifica: si una página olvida title, TypeScript protesta en el editor antes de que el sitio salga sin título. El componente se coloca en el <head> del layout y cada página le pasa sus dos o tres datos, con lo que el <head> deja de ser una lista de etiquetas escritas a mano y pasa a ser el resultado de invocar una función bien tipada.

ASTRO
---// src/layouts/Base.astroimport SEO from '../components/SEO.astro';const { title, description } = Astro.props;---<html lang="es">  <head>    <meta charset="utf-8" />    <SEO title={title} description={description} />  </head>  <body><slot /></body></html>

Resiste la tentación de que este componente haga demasiado. Su trabajo es emitir metadatos, no maquetar; si mañana suma las etiquetas Open Graph y el bloque JSON-LD de las próximas lecciones, seguirá siendo una sola pieza con una sola razón para cambiar. Y como no depende de nada visual, puedes razonarlo y probarlo aislado: dado un conjunto de props, ¿emite las etiquetas correctas? Esa pregunta tiene una respuesta verificable, que es justo lo que se pierde cuando el SEO se dispersa por veinte plantillas.

La canónica autorreferente con Astro.url

Una misma página puede alcanzarse por varias direcciones —con barra final y sin ella, con parámetros de campaña, por http y por https— y el buscador puede tratarlas como duplicados que se reparten la autoridad. La <link rel="canonical"> corta ese nudo nombrando la dirección verdadera. La práctica robusta es la canónica autorreferente: cada página declara como canónica su propia URL limpia, derivada de Astro.site más Astro.url.pathname, nunca escrita a mano.

Derivarla en vez de copiarla tiene una consecuencia valiosa: es correcta por construcción en cualquier entorno, porque se recalcula de la fuente. Un matiz fácil de olvidar es que la canónica debe casar con la forma real de tus URLs —la que fija trailingSlash—; tomarla de Astro.url en lugar de componerla a mano evita justo ese desajuste, porque usa la ruta tal como el sitio la resuelve. Y como el componente <SEO /> la calcula por defecto, ninguna página puede quedarse sin ella salvo que la sobrescriba a propósito.

Valores por defecto: que ninguna página quede desnuda

El poder real de encerrar el SEO en un componente es que puede fallar hacia la seguridad. Si una página olvida un dato, el componente no debe emitir una etiqueta vacía, sino un valor por defecto sensato: una descripción genérica del sitio, la imagen social de reserva, un index, follow implícito para las páginas normales. Así el peor caso de un descuido no es una página muda ante el buscador, sino una página con metadatos correctos aunque menos afinados.

ASTRO
---// src/components/SEO.astro, con defaults defensivosconst {  title,  description = 'Guía de Neovim, Astro y desarrollo moderno',  image = '/og-default.png',  noindex = false,} = Astro.props;const canonical = new URL(Astro.url.pathname, Astro.site);const ogImage = new URL(image, Astro.site);---<title>{title ? `${title} · nvim-dios` : 'nvim-dios'}</title><meta name="description" content={description} /><link rel="canonical" href={canonical.href} /><meta name="robots" content={noindex ? 'noindex, nofollow' : 'index, follow'} />

Fíjate en que el <title> contempla el caso de la portada, donde el patrón página · marca sobra y basta el nombre del sitio a secas. Estos condicionales viven en un único lugar, de modo que la política de metadatos del sitio entero cabe en un fichero que puedes leer de un vistazo y razonar por completo. Cambiar la descripción por defecto, el sufijo del título o la imagen de reserva es editar una línea, y el cambio se propaga a cada ruta sin que ninguna tenga voto ni pueda desviarse.