Orientación constante
En cualquier página, el visitante ve el mapa completo y sabe a dónde ir. La misma navegación en todas partes evita callejones sin salida y mantiene a la gente explorando en lugar de abandonar.
La franja de marca y menú que se asienta bajo el topbar y acompaña al visitante en cada página. Si el topbar susurra «aquí estamos», el header responde a las dos preguntas que todos traen al llegar: «¿de quién es esto?» y «¿a dónde puedo ir?».
Esta página no resume el módulo: lo abre por completo. Verás qué problema resuelve y por qué se gana su lugar fijo, de qué piezas se compone, cómo se comporta en el teléfono, dónde encaja en el armado de la página y, al final, cómo está construido por dentro —del criterio de diseño a la línea de código.
Todo descansa sobre una idea que se repite en cada módulo de esta plantilla: una sola fuente de verdad. El menú no se escribe a mano en ningún componente; vive en un único array, NAV, dentro de site.ts. De ahí nacen, a la vez y sin copiar nada, el menú de escritorio, los paneles desplegables y la versión móvil. Cambias una sección una vez y aparece, idéntica, en todo el sitio.
Definición
La barra de cabecera: logotipo y navegación principal, en una franja constante que corona cada página justo debajo del topbar.
El header —o cabecera— es la barra que encabeza todas las páginas del sitio, pegada bajo el topbar. Reúne las dos cosas que cualquier visitante busca por reflejo apenas llega: la marca, arriba a la izquierda, que dice de quién es el sitio y funciona como botón de «volver al inicio»; y el menú, con las secciones por las que puede moverse. Junta identidad y orientación en una sola línea.
Su virtud no es destacar, sino ser fiable. Aparece en el mismo lugar, con la misma forma, página tras página —y esa constancia es justo lo que lo vuelve útil: el visitante aprende dónde está el menú una sola vez y lo encuentra ahí para siempre. Es la señalización de un buen edificio: discreta a propósito, porque su trabajo es que nunca tengas que detenerte a pensar por dónde seguir.
Función e importancia
Hace tres trabajos a la vez, en todas las páginas: orientar con el menú, anclar la marca con el logotipo y dejar la conversión a un clic con el CTA.
Su función es ser el sistema de orientación del sitio. Mientras el hero presenta y el contenido convence, el header está ahí, callado, resolviendo en todo momento tres preguntas que el visitante trae consigo: de quién es esto, a dónde puede ir y cómo dar el siguiente paso. Tener esas respuestas siempre a la vista es lo que convierte un puñado de páginas sueltas en un sitio que se recorre con confianza.
Y por eso pesa tanto: es el elemento más mirado y más usado de todo el sitio. Una navegación confusa, o un logotipo que no lleva a la home, cuestan visitas en el acto —porque rompen expectativas que la gente ni siquiera sabe que tiene—. Bien resuelto, en cambio, se vuelve invisible: se usa sin pensar. Y esa es, justamente, la señal de que está bien hecho.
En cualquier página, el visitante ve el mapa completo y sabe a dónde ir. La misma navegación en todas partes evita callejones sin salida y mantiene a la gente explorando en lugar de abandonar.
El logotipo, fijo arriba a la izquierda, recuerda de quién es el sitio y ofrece el «volver al inicio» que casi todos buscan por reflejo. Es el ancla a la que se regresa cuando uno se pierde.
Escritorio y móvil salen del mismo array (NAV). El visitante encuentra lo mismo en cualquier pantalla y tú editas en un solo lugar, sin dos menús que se contradigan con el tiempo.
Anatomía
Cuatro piezas, cada una con un trabajo: la marca, la navegación, los paneles que ordenan lo que tiene hijos y un único botón de conversión.
Cada pieza se gana su lugar. El logotipo ancla la identidad y devuelve a la home; la navegación reparte hacia las secciones; los paneles despliegan los hijos de una sección sin saturar la barra; y el CTA mantiene la conversión a un clic. Nada sobra, y nada compite con otra cosa por la atención.
Abajo lo ves montado con los datos reales de la plantilla —la marca sale de site.ts y los enlaces, de NAV—. Cada punto numerado se explica en su tarjeta: qué resuelve y de qué dato nace, para que distingas a simple vista qué es diseño y qué es contenido. En el teléfono, esta misma barra se pliega tras el botón ☰; ese menú móvil lo abrimos a fondo más adelante.
La marca, a la izquierda y enlazada a la home. Es el ancla de identidad y el «volver al inicio» que todos buscan por instinto. Aquí sí va el logotipo —en el topbar, no—.
Dato SITE.brand · SITE.name
Las secciones del sitio. Ningún enlace se escribe a mano: el componente recorre NAV, la misma lista para escritorio y móvil. Por debajo de 1024 px se pliega en el menú ☰.
Dato NAV
Las secciones con hijos despliegan un panel al pasar el cursor o con el teclado. Su contenido nace de la taxonomía (productos, servicios, módulos), no de una lista aparte que mantener en paralelo.
Dato NAV[].panel · items
El botón de conversión, siempre visible a la derecha. Su enlace no se teclea: lo arma waUrl() con el mensaje precargado de WA_MESSAGES, para que la conversación empiece con contexto.
Dato waUrl(WA_MESSAGES.cotizacion)
mega vs dropdown
El panel que cuelga de un ítem de navegación no es siempre igual: la anchura, el layout y la densidad de información cambian según cuántos hijos tiene esa sección y qué tan visual necesita ser.
El parámetro panel de cada NavItem controla cuál se despliega. El mega panel ocupa todo el ancho de la barra y organiza los hijos en una cuadrícula — es el indicado cuando hay cuatro o más categorías con descripción, cuando quieres añadir una imagen editorial o cuando la sección es la más importante del catálogo (p. ej. «Productos»). El dropdown es una lista compacta, vertical, anclada bajo el ítem padre — correcto para secciones secundarias con pocos hijos y sin necesidad de foto ni descripción (p. ej. «Servicios», «Recursos»).
Ambos nacen del mismo NAV: lo único que cambia es el valor del campo panel y la plantilla CSS que activa. Un ítem sin panel = enlace directo, sin desplegable.
panel: 'mega' — Cuadrícula ancha debajo de toda la barra.
Usa para secciones principales con ≥4 categorías.
panel: 'dropdown' — Lista compacta anclada al ítem.
Usa para secciones secundarias con ≤4 enlaces breves.
Variantes
El de esta plantilla es un header clásico, pero la cabecera cambia de forma según lo que un sitio necesita mostrar y vender.
No existe un único header, sino una franja de cabecera que cada tipo de proyecto afina a su objetivo. Una tienda con catálogo profundo abre un mega-menú; una marca de moda centra el logotipo para que respire; una aplicación cambia secciones por acciones de usuario. Mismo lugar en la página, prioridades distintas.
Abajo, seis variantes reales —cada una con su réplica en vivo y el tipo de proyecto donde rinde mejor—. No están para copiarlas tal cual, sino para que reconozcas cuál encaja con tu caso y veas cómo el mismo molde se reescribe sin perder su sitio.
Responsive y móvil
En el móvil la navegación no se encoge: se replantea. La barra de enlaces se pliega tras el botón ☰ y todo pasa a regirse por el pulgar.
Una fila de secciones no cabe en la pantalla de un teléfono, así que el header cambia de modo en lugar de apretarse. La marca se queda donde está; la navegación se recoge detrás del botón ☰ —la hamburguesa— y se despliega como un panel a pantalla completa. Es un gesto que todo el mundo ya conoce, y por eso funciona: no hay que enseñar a usarlo.
A partir de ahí, manda la ergonomía. Las secciones con hijos se abren en acordeón para no saltar de pantalla; los destinos más usados pueden bajar a una barra inferior, donde el pulgar llega sin esfuerzo; y el header puede condensarse al hacer scroll para devolverle altura al contenido. Abajo, cuatro patrones, cada uno con su vista en el teléfono y una receta comentada lista para adaptar.
Por debajo de 1024 px, la fila de enlaces desaparece y aparece el botón ☰, que abre un panel a pantalla completa con las mismas secciones —generadas del mismo NAV—. Un detalle que se olvida y se nota: mientras el panel está abierto, hay que bloquear el scroll del fondo.
<!-- HEADER MÓVIL · hamburguesa + panel (drawer)
En móvil la barra de enlaces se oculta y aparece el botón ☰,
que abre un panel a pantalla completa con el MISMO NAV que el
escritorio. Mientras está abierto, el fondo no hace scroll. -->
<button class="hdr-burger" aria-label="Abrir menú"
aria-expanded="false" aria-controls="mobile-nav">☰</button>
<nav id="mobile-nav" class="mobile-nav" aria-hidden="true"><!-- enlaces de NAV --></nav>
<script>
const btn = document.querySelector('.hdr-burger');
const nav = document.getElementById('mobile-nav');
btn.addEventListener('click', () => {
const abierto = nav.getAttribute('aria-hidden') === 'false';
nav.setAttribute('aria-hidden', abierto ? 'true' : 'false');
btn.setAttribute('aria-expanded', abierto ? 'false' : 'true');
document.body.style.overflow = abierto ? '' : 'hidden'; // bloquea el fondo
});
</script> Las entradas con hijos (los mega y dropdown del escritorio) se vuelven acordeón: un toque expande sus subsecciones, y solo una queda abierta a la vez para no abrumar. La transición de altura se resuelve con un truco de CSS moderno, sin medir píxeles.
/* SUBMENÚS EN MÓVIL · acordeón con transición real de altura
El truco moderno: animar grid-template-rows de 0fr a 1fr.
No hace falta adivinar un max-height; el grid mide el contenido
por ti y la animación queda suave con 2 enlaces o con 12. */
.mob-panel {
display: grid;
grid-template-rows: 0fr; /* cerrado */
transition: grid-template-rows .25s ease;
}
.mob-panel.is-open { grid-template-rows: 1fr; } /* abierto */
/* El hijo debe poder colapsar a 0: de ahí el overflow:hidden. */
.mob-panel > * { min-height: 0; overflow: hidden; }
/* JS · alternar .is-open al tocar, y solo una sección abierta a la vez. */ En apps y catálogos con pocos destinos clave, la navegación baja al borde inferior —lo más cómodo de alcanzar con una mano—, con entre tres y cinco íconos, objetivos de 44 px y respeto por el área segura del iPhone.
/* NAVEGACIÓN INFERIOR (bottom-nav) · estilo app
3–5 destinos en la «zona del pulgar». Cada objetivo táctil
mide ≥ 44 px y la barra respeta el área segura del iPhone
(la franja de gestos) con env(safe-area-inset-bottom). */
@media (max-width: 640px) {
.bottom-nav {
position: fixed; inset: auto 0 0 0; z-index: var(--z-sticky);
display: grid; grid-auto-flow: column; grid-auto-columns: 1fr;
background: var(--c-white); border-top: 1px solid var(--c-border);
padding-bottom: env(safe-area-inset-bottom);
}
.bottom-nav a {
min-height: 44px; display: grid; place-items: center; gap: 2px;
font-size: var(--text-xs); color: var(--c-ink-2); text-decoration: none;
}
} Al bajar, el header encoge —menos alto, una sombra sutil— para cederle pantalla al contenido; al volver arriba, recupera su tamaño. Da aire en lecturas largas sin esconder del todo la navegación.
/* HEADER QUE SE CONDENSA AL HACER SCROLL
Al bajar, el header encoge (menos alto + sombra) para ceder
pantalla; al volver arriba, recupera su tamaño. La transición
vive en CSS; el JS solo alterna una clase. */
.site-header { transition: height .2s ease, box-shadow .2s ease; }
.site-header.is-shrink { height: 56px; box-shadow: var(--shadow-md); }
/* JS · passive:true le avisa al navegador que no haremos
preventDefault → el scroll sigue fluido:
addEventListener('scroll', () =>
header.classList.toggle('is-shrink', scrollY > 40),
{ passive: true }); */ Posición
En la segunda franja desde arriba: pegado bajo el topbar y por encima del contenido, de borde a borde. Es el segundo bloque del sitio en el orden de lectura.
El orden del armado es deliberado. PageLayout apila el chrome siempre igual: primero el topbar (la barra utilitaria de contacto), debajo el header (marca y navegación), luego las migas de pan y, recién entonces, el contenido de cada página. Ese orden acompaña a cómo lee la gente: el ojo va arriba a la izquierda buscando la marca, y arriba a la derecha buscando el menú y la acción.
En esta plantilla el header no es fijo: se desplaza con el contenido al hacer scroll. Es una decisión a conciencia, y tiene un detalle técnico bonito detrás: los paneles mega y dropdown se posicionan respecto al header (position: absolute sobre un header position: relative), así que viajan anclados a él en lugar de quedar flotando pegados al viewport. Arriba viste el patrón alterno —condensarse o quedar fijo— para cuando un proyecto lo pida; y su altura, como todo, sale de un token: --header-height (64 px, 60 en pantallas menores).
Implementación
Un componente que no guarda ningún enlace: recorre NAV para generar las tres vistas —escritorio, paneles y móvil— desde una sola fuente.
El header vive en Header.astro, pero su menú no está dentro: lo genera iterando NAV, el array de site.ts que es la única fuente de verdad. El mismo recorrido produce la barra de escritorio, los paneles desplegables y el menú móvil. Añadir, quitar o reordenar una sección es editar ese array, y los tres se actualizan solos —sin que existan dos menús que mantener en sincronía—.
Y aquí conviene una distinción de arquitectura que vale para todo el sitio: la navegación es estructura, no contenido editorial. Por eso vive en un archivo de configuración tipado (TypeScript), donde un menú mal formado lo caza el compilador, y no en Markdown —que es para lo que sí es contenido: los artículos del blog (colección .mdx) o las fichas del catálogo—. Los hijos de cada panel, de hecho, salen de esa taxonomía, de modo que el menú nunca se desfasa de lo que el sitio realmente ofrece.
// site.ts — la navegación es CONFIG, no contenido editorial:
// vive en un array TIPADO (no en Markdown). Editar el menú = editar esto,
// y un menú mal formado lo caza el compilador antes de publicar.
export type NavItem = {
label: string;
href: string;
panel?: 'mega' | 'dropdown'; // ¿despliega panel? y de qué tipo
items?: { label: string; href: string; desc?: string }[];
};
export const NAV: readonly NavItem[] = [
{ label: 'Productos', href: '/productos', panel: 'mega', items: /* …de la taxonomía… */ [] },
{ label: 'Servicios', href: '/servicios', panel: 'dropdown', items: /* …de la taxonomía… */ [] },
{ label: 'Blog', href: '/blog' }, // sin panel = enlace directo
{ label: 'Contacto', href: '/contacto' },
]; ---
// Header.astro — el menú NO se escribe a mano: se ITERA NAV.
// El mismo recorrido alimenta escritorio, paneles y móvil.
import { NAV } from '@config/site'
---
<nav aria-label="Navegación principal">
<ul>
{NAV.map((item) => (
<li>
<a href={item.href}>{item.label}</a>
{/* ¿La sección tiene hijos? Entonces despliega su panel. */}
{item.panel && (
<div class="panel" role="region" aria-label={item.label}>
{item.items?.map((sub) => (
<a href={sub.href}>{sub.label}</a>
))}
</div>
)}
</li>
))}
</ul>
</nav>
El componente recorre NAV y, según cada entrada tenga
panel: 'mega', 'dropdown' o ninguno, dibuja un panel ancho,
una lista compacta o un enlace directo. Un pequeño ayudante, navId(), genera
un id estable —sin acentos— para enlazar cada sección con su panel; e
isActive() compara la ruta actual (Astro.url.pathname) para
resaltar dónde estás parado.
La interacción está pensada para el teclado tanto como para el cursor: los paneles abren al
enfocar y se cierran con un temporizador de gracia (unos 120 ms), para que
no desaparezcan si el puntero apenas los cruza; Escape los cierra y devuelve el
foco, y un overlay atenúa el fondo. En móvil, ese mismo NAV se vuelve
un acordeón accesible y se bloquea el scroll de la página. Nada de esto necesita un
framework: es un <script> del lado del cliente que Astro envía tal cual,
sin hidratar islas —HTML y JavaScript mínimo, que es la apuesta de Astro—.
Buenas prácticas
La diferencia entre un header que guía y uno que confunde cabe en un puñado de hábitos.
Ninguno de estos hábitos es un capricho: salen de mirar cómo usa la gente una cabecera de verdad. Un header que ayuda mantiene el menú corto, la marca enlazada y una sola acción clara; uno que estorba multiplica botones, esconde la navegación en niveles o arrastra dos menús que terminan contradiciéndose.
La buena noticia es que se sostienen casi solos en cuanto respetas la fuente única: el menú nace de NAV, el CTA de waUrl() y los colores y espacios de los tokens. Abajo, enfrentados, lo que conviene y lo que conviene evitar.