Complemento del blog · Sidebar

El Sidebar: la columna que enlaza todo

La barra lateral junto a los artículos. Reúne categorías, temas, lecturas recomendadas y puentes al resto del sitio. No es decoración: es el motor de enlazado interno del blog —y, al final, una acción clara.

Esta página no es una ficha técnica: es el complemento entero, abierto y explicado. Qué problema resuelve y por qué gana su lugar junto al contenido, de qué widgets se compone, cómo se comporta en el teléfono, dónde encaja y, al final, cómo está construido —del criterio de diseño a la línea de código—.

Con una particularidad que conviene marcar desde el principio: no se escribe a mano. Sus listas —categorías, temas, recientes— se calculan desde la colección de artículos, así que publicar un .mdx las actualiza solas. Una sola fuente de verdad; el sidebar nunca se desincroniza del blog real.

Definición

¿Qué es el sidebar del blog?

La columna secundaria junto al contenido. Agrupa bloques de navegación —widgets— que conectan el artículo con el resto del blog y del sitio.

El sidebar (barra lateral) es la columna que acompaña al contenido principal del blog. En escritorio vive a un lado de los artículos; en móvil baja debajo. Cada bloque que contiene es un «widget»: categorías, temas, lecturas recomendadas, accesos al sitio y una caja de acción. Vista de lejos parece decoración; vista de cerca hace un trabajo concreto: ofrecer el siguiente paso.

No se inventó aquí: es un patrón consolidado de blogs y medios —el lector termina (o ni siquiera) un artículo y tiene a la mano por dónde seguir—. En esta plantilla, además, no es estático: sus listas se derivan de la colección de artículos, de modo que reflejan siempre el contenido publicado, sin mantenerse a mano.

Función e importancia

¿Para qué sirve?

Hace tres trabajos a la vez: reparte autoridad por enlazado interno, encadena la visita en más páginas y conecta el contenido con las páginas de negocio.

Su función es cerrar la brecha entre «leí esto» y «¿qué sigue?». Un artículo aislado termina en un callejón; el sidebar lo convierte en un cruce: desde aquí se va a la categoría, al tema, a otro artículo o a la página que cotiza. Es, en una sola columna, el mapa de salidas del contenido.

Y por eso pesa fuera de proporción a su tamaño. Para el SEO, es enlazado interno con anchor text real que reparte autoridad y da contexto temático. Para el negocio, es el puente del contenido editorial a las fichas de servicio o producto. Para el lector, es lo que vuelve una entrada un recorrido. Tres efectos, una sola pieza.

Enlazado interno que reparte autoridad

Cada widget es un puñado de enlaces con anchor text real hacia categorías, temas, otros artículos y páginas de negocio. Para el buscador, eso reparte equity interno y da contexto temático; para el lector, es el siguiente paso siempre a la vista. El sidebar es, sobre todo, el motor de interlinking del blog.

Más páginas por sesión, menos rebote

Un artículo que termina sin salida pierde al lector. Con «lecturas recomendadas» y los archivos de categoría/tema a un clic, la visita encadena páginas en vez de cerrarse. Es la diferencia entre una entrada y un recorrido.

Se alimenta solo (cero mantenimiento)

Las listas no se escriben a mano: salen de la colección de artículos. Publicar un .mdx recalcula las categorías, los temas y los recientes. El sidebar siempre refleja el blog real, sin una segunda lista que mantener ni desincronización posible.

Anatomía

¿Qué lleva el sidebar?

Cinco widgets: categorías con conteo, nube de temas, lecturas recomendadas, accesos al sitio y la caja de conversión que lo cierra.

Cada widget cumple un papel claro. Las categorías ordenan por sección; los temas conectan por concepto transversal; las lecturas recomendadas retienen al lector; «explora el sitio» cruza hacia el negocio; y el CTA cierra con la acción. Nada sobra, y el orden de lectura va de lo más editorial a lo más comercial.

Abajo, el ejemplo en vivo —réplica anotada a escala del componente—. Cada punto numerado se desglosa en su tarjeta: qué resuelve y de qué prop del componente sale. A diferencia de un sidebar escrito a mano, aquí las listas vienen de la colección de artículos, así que publicar actualiza la columna sola.

1

Categorías (con conteo)

La lista de categorías del blog con el número de artículos de cada una. Cada nombre enlaza a su archivo /blog/categoria/<slug>. El conteo es una señal de volumen para el lector y reparte autoridad hacia las páginas de categoría.

Dato categorias[] · { label, href, count }

2

Temas (nube de tags)

Los tags más usados, como chips, hacia /blog/tag/<tag>. Conectan artículos por tema transversal —algo que la categoría única no captura— y dan rutas de descubrimiento al lector que llegó buscando un concepto.

Dato temas[] · { label, href, count }

3

Lecturas recomendadas

Una lista corta de artículos —los más recientes o destacados— para mantener al lector dentro del blog. Es el «sigue leyendo» que sube las páginas por sesión y baja el rebote.

Dato posts[] · { label, href, desc? }

4

Explora el sitio

Puentes a las páginas de conversión —Servicios, Productos, Módulos, Contacto—. Es el cross-linking que conecta el contenido editorial con el negocio: del artículo a la ficha que cotiza.

Dato enlaces[] · { label, href, desc? }

5

CTA de conversión

La caja final con la acción: Preguntar por WhatsApp. No es una sección más; su enlace no se teclea, lo arma waUrl() con el mensaje precargado de WA_MESSAGES (regla D4). Cierra la columna con una intención clara.

Dato cta · waUrl(WA_MESSAGES.blog)

Variantes

Otros diseños y aplicaciones

La de esta plantilla es una columna a la derecha con cinco widgets, pero el sidebar cambia de cara según lo que la página necesita: navegación, búsqueda, índice de lectura o franja al pie.

No hay un único modelo: hay una misma idea —una columna de apoyo que conecta— que cada tipo de proyecto ajusta. Una revista quita el CTA y deja navegación pura; una base de conocimiento suma un buscador; una guía larga la convierte en índice del artículo; un diseño minimal la baja a una franja al pie.

Abajo, seis variantes —las primeras son configuraciones reales del componente (cambiando props o el orden del grid), y un par son extensiones propuestas que requerirían añadir un widget—. Cada una con su réplica en vivo y el tipo de proyecto donde rinde mejor.

  • Derecha sticky (esta plantilla)

    Negocio · Blog

    La del listado /blog: columna a la derecha que se queda fija al hacer scroll en escritorio y baja debajo del contenido en móvil. Es la más segura y la que mejor equilibra lectura y navegación. Configuración real del componente.

  • A la izquierda

    Documentación · App

    La misma columna, pero antes del contenido. Funciona en docs y paneles donde la navegación pesa tanto como el texto. Se logra invirtiendo el orden de las columnas del grid; el componente no cambia.

  • Solo navegación (sin CTA)

    Editorial · Revista

    Cuando la página no busca una venta inmediata, se omite la prop cta y la columna queda 100% navegacional: categorías, temas y recomendados. El componente lo soporta de fábrica —cta es opcional—.

  • Con buscador arriba

    Blog grande · Knowledge base

    Extensión propuesta: una caja de búsqueda como primer widget, encima de las categorías. Útil cuando el archivo crece y buscar gana al navegar. Requiere añadir un slot/prop de búsqueda al componente.

  • Índice del artículo (TOC)

    Guías largas · Tutoriales

    En la página del artículo, el sidebar puede mostrar «en este artículo» —anclas a cada encabezado H2/H3— que siguen el scroll. Variante del mismo patrón sticky, orientada a lectura larga en vez de a navegación del blog.

  • Franja al pie (sin columna)

    Mobile-first · Minimal

    Sin columna lateral: los mismos widgets se reparten en una franja horizontal al final del contenido. Para diseños de una sola columna donde no se quiere barra lateral pero sí el interlinking. Es CSS por encima; los datos no cambian.

Responsive y móvil

Cómo se comporta en el teléfono

En móvil el sidebar no compite con el contenido: baja debajo. De ahí, según el caso, puede colapsarse en acordeones o quedarse sticky en escritorio.

En escritorio la columna vive cómoda a la derecha, fija al scroll. En el teléfono no hay ancho para dos columnas, así que el grid pasa a una sola y el sidebar cae DEBAJO del contenido —el artículo siempre primero—. Es lo más seguro y lo que ya hace el listado de la plantilla, sin tocar el componente.

A partir de ahí, tres patrones según lo que pida la página: colapsar cada widget en acordeones para ahorrar scroll, controlar el orden con order cuando el marcado no viene en el orden deseado, y el sticky de escritorio (que se desactiva con prefers-reduced-motion). Cada uno, abajo, con su vista en el teléfono y su receta.

1 · Debajo del contenido (default)

Mobile-first: el grid pasa a 1fr y el sidebar cae bajo el artículo. Como en el HTML el contenido va primero, queda arriba sin esfuerzo; si no, se reordena con order. El lector recibe el texto antes que la navegación.

CSS · apilar el sidebar debajo
/* MÓVIL · el sidebar baja DEBAJO del contenido (default).
   Una sola columna y el ORDEN del HTML manda: primero el
   artículo (.blog__main), luego la barra (.blog__aside). */

.blog { grid-template-columns: 1fr; }   /* apilado */

/* El artículo va antes que el sidebar en el HTML, así que
   en móvil queda arriba sin tocar nada. Si el sidebar fuera
   primero en el marcado, se reordena con 'order'. */
@media (max-width: 1023px) {
  .blog__main  { order: 1; }
  .blog__aside { order: 2; }
}

2 · Widgets colapsables (extensión)

Cuando hay muchos widgets, apilarlos abiertos hace la página muy alta. Metiendo cada uno en <details>, en móvil arrancan cerrados y el lector abre el que le interesa; en escritorio van desplegados. Cero JavaScript: es HTML nativo.

CSS · acordeones en móvil
/* MÓVIL · widgets colapsables para ahorrar scroll (extensión).
   Cada widget va dentro de <details>; en móvil arranca cerrado
   y el lector abre el que le interesa. En escritorio, abierto. */

@media (max-width: 1023px) {
  .bsb__w > details > summary {
    cursor: pointer; list-style: none;
    padding: var(--sp-3) var(--sp-4);
    font-weight: var(--weight-semibold);
  }
  .bsb__w > details:not([open]) > summary::after { content: ' ▾'; }
}
@media (min-width: 1024px) {
  .bsb__w > details { open: true; }   /* siempre desplegado */
}

3 · Sticky bajo el header (escritorio)

En pantallas ≥1024 px la columna se queda fija mientras el artículo hace scroll, usando la altura real del header como offset para no quedar tapada. Se desactiva con prefers-reduced-motion para quien prefiere menos movimiento.

CSS · sticky + reduced-motion
/* ESCRITORIO · sticky bajo el header; estático si se prefiere
   menos movimiento. El offset usa la altura real del header. */

@media (min-width: 1024px) {
  .blog__aside {
    position: sticky;
    top: calc(var(--header-height, 72px) + var(--sp-4));
  }
}

/* Respeta a quien pide menos animación: deja de flotar. */
@media (prefers-reduced-motion: reduce) {
  .blog__aside { position: static; }
}

Posición

¿Dónde se coloca?

Una vez por página, junto al contenido: a la derecha del listado /blog y de cada artículo. Dentro del container, no de borde a borde.

El sidebar entra en el cuerpo de la página, no en el chrome. En el listado /blog acompaña a la rejilla de tarjetas; en el artículo (ArticleLayout) acompaña a la prosa. Siempre en su propia columna del grid —contenido a la izquierda, barra a la derecha— y dentro del container central, a diferencia de franjas full-width como el menú de secciones.

Va una sola vez por página y no se repite. En escritorio es sticky para acompañar la lectura; en móvil baja debajo del contenido. Su lugar natural es la sección de contenido del blog: ni en la home ni en fichas de producto, donde el interlinking lo resuelven otras piezas (vitrina, categorías a fondo, CTA banner).

Piezas cercanas: el listado del blog (donde vive esta columna), la paginación (cómo se parte el listado) y el menú de secciones (interlinking, pero full-width al cierre).

Implementación

Cómo está construido

Un componente presentacional (BlogSidebar.astro) que solo pinta lo que recibe, alimentado por listas que el listado /blog calcula desde la colección de artículos.

El componente vive en BlogSidebar.astro y expone una API pequeña a propósito: categorias, temas, posts, enlaces y cta. No sabe nada del blog —no llama a getCollection ni inventa datos—: solo recorre los arrays y pinta cada widget. Esa separación lo hace reutilizable (un sidebar de artículo puede pasarle otras listas) y trivial de testear.

El trabajo de datos vive en la página, no en el componente. El listado /blog lee la colección una vez y deriva las tres listas dinámicas —categorías y temas con conteo, y los recientes—; los accesos al sitio y el CTA son fijos. Así, publicar un .mdx recalcula el sidebar entero, y el enlace de WhatsApp se arma con waUrl(WA_MESSAGES.blog), nunca a mano (regla D4).

Astro · uso del componente desde la página
---
// USO · el listado /blog le pasa los datos ya calculados.
// El componente es presentacional: solo pinta lo que recibe.
import BlogSidebar from '@components/BlogSidebar.astro'
import { waUrl, WA_MESSAGES } from '@config/site'
---

<BlogSidebar
  categorias={categorias}   {/* [{ label, href, count }] */}
  temas={temas}             {/* [{ label, href, count }] */}
  posts={posts}             {/* [{ label, href, desc? }] */}
  enlaces={enlaces}         {/* [{ label, href, desc? }] */}
  cta={{ label: 'Preguntar por WhatsApp', href: waUrl(WA_MESSAGES.blog) }}
/>
TypeScript · cómo se calculan los widgets desde la colección
---
// DATA-DRIVEN · los widgets se calculan desde la colección, no a mano.
import { getCollection } from 'astro:content'

const articulos = (await getCollection('articulos', ({ data }) => !data.draft))
  .sort((a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf())

// 1) Categorías con conteo  →  /blog/categoria/<slug>
const cuenta = new Map<string, number>()
for (const a of articulos) cuenta.set(a.data.category, (cuenta.get(a.data.category) ?? 0) + 1)
const categorias = [...cuenta].sort((a, b) => b[1] - a[1])
  .map(([slug, count]) => ({ label: slug, href: `/blog/categoria/${slug}`, count }))

// 2) Temas (tags) más usados  →  /blog/tag/<tag>
const tags = new Map<string, number>()
for (const a of articulos) for (const t of a.data.tags ?? []) tags.set(t, (tags.get(t) ?? 0) + 1)
const temas = [...tags].sort((a, b) => b[1] - a[1]).slice(0, 12)
  .map(([label, count]) => ({ label, href: `/blog/tag/${label}`, count }))

// 3) Lecturas recomendadas  →  5 más recientes
const posts = articulos.slice(0, 5).map((a) => ({ label: a.data.title, href: `/blog/${a.id}` }))
---
CSS · el layout de dos columnas (sticky)
/* EL LAYOUT · una columna en móvil; contenido + sidebar en escritorio. */
.blog { display: grid; grid-template-columns: 1fr; gap: var(--sp-6); }
.blog__main { min-width: 0; }   /* evita que un <pre> desborde la columna */

@media (min-width: 1024px) {
  .blog { grid-template-columns: minmax(0, 1fr) 20rem; align-items: start; }
  /* el aside sigue al scroll, sin quedar tapado por el header sticky */
  .blog__aside { position: sticky; top: calc(var(--header-height, 72px) + var(--sp-4)); }
}

En concreto: el componente recorre cada lista con Array.prototype.map y solo emite el widget si tiene datos (categorias.length > 0, etc.), de modo que una lista vacía no deja una caja huérfana. Cada widget es una <section> con su <h2>; «explora el sitio» es un <nav aria-label> porque es navegación pura.

La accesibilidad es de fábrica: la columna es un <aside aria-label> (landmark secundario, no compite con <main>), los enlaces tienen foco visible (:focus-visible) y el conteo de cada categoría lleva su aria-label. Cero JavaScript: es HTML + CSS estático generado en build, y el sticky se apaga con prefers-reduced-motion.

Buenas prácticas

Qué hacer y qué evitar

La diferencia entre un sidebar que ayuda y uno que estorba cabe en un puñado de hábitos —empezando por no repetir el menú del header—.

Ninguno de estos hábitos es capricho: salen de mirar dónde tropieza un blog cuando la columna lateral crece sin criterio. Un sidebar útil mantiene pocos widgets, calcula sus listas desde una sola fuente y cierra con un CTA. Uno que estorba acumula cajas, repite el menú principal o tapa el contenido en móvil.

La buena noticia es que casi todo se sostiene solo cuando los datos salen de la colección y el CTA usa waUrl(). Abajo, lo que conviene y lo que conviene evitar, enfrentados.

Sí conviene

  • Usa anchor text descriptivo en cada enlace (el nombre de la categoría/tema), nunca «clic aquí».
  • Calcula las listas desde la colección de artículos: una sola fuente, cero listas a mano.
  • Mantén 3–5 widgets: categorías, temas, recomendados, sitio y un CTA. Más es ruido.
  • Déjalo sticky en escritorio para que acompañe la lectura, y debajo del contenido en móvil.
  • Cierra con UN solo CTA y arma su enlace con waUrl() (regla D4).

Mejor evita

  • No metas el menú principal completo aquí: el sidebar complementa al header, no lo repite.
  • No lo conviertas en un muro de widgets (archivos por mes, blogroll infinito, banners).
  • No pongas el sidebar ENCIMA del contenido en móvil: el artículo va primero.
  • No tecles el wa.me a mano en el CTA: usa waUrl(WA_MESSAGES.blog) (regla D4).
  • No dupliques el mismo CTA tres veces: una caja de conversión basta.
¿Necesitas ayuda?