Introducción
En este tutorial detallado vas a aprender a crear una cabecera “pegada” (sticky/fixed) en WordPress que muestra u oculta una sombra cuando el usuario hace scroll. La idea es mantener la cabecera visible y limpia cuando la página está en la parte superior y añadir una sombra sutil cuando el usuario se desplaza, para que la cabecera se perciba por encima del contenido. El resultado combina CSS para el estilo y una pequeña porción de JavaScript para detectar el scroll (método recomendado por compatibilidad). También incluyo una alternativa CSS pura usando CSS :has() (experimental y con soporte limitado).
Resumen de la solución
- HTML: marca la cabecera con una clase clara (por ejemplo .site-header).
- CSS: fija la cabecera, define la transición de la sombra y asegura que el contenido no salte al aparecer la cabecera.
- JavaScript ligero: añade/quita una clase (por ejemplo .is-scrolled) según la posición de scroll para activar la sombra.
- Integración en WordPress: se muestran ejemplos para añadir CSS/JS a través de functions.php con enqueue.
HTML (estructura recomendada)
Coloca este HTML en tu plantilla de cabecera (por ejemplo header.php) o adapta las clases si tu tema ya tiene sus propias clases. El ejemplo es genérico y claro para entender dónde actúa el CSS/JS.
ltheader class=site-header role=bannergt
ltdiv class=wrapgt
lta class=site-logo href=/ title=IniciogtMi sitiolt/agt
ltnav class=site-nav role=navigationgt
ltulgt
ltligtlta href=/sobregtSobrelt/agtlt/ligt
ltligtlta href=/contactogtContactolt/agtlt/ligt
lt/ulgt
lt/navgt
lt/divgt
lt/headergt
CSS (estilos principales)
Este CSS fija la cabecera, aplica una transición suave y define la sombra que aparecerá cuando la cabecera tenga la clase .is-scrolled. Ajusta variables (colores, alturas) a tu tema.
:root{
--header-height: 68px / Ajustar a la altura real de la cabecera /
--header-bg: rgba(255,255,255,0.98)
--header-z: 1000
--shadow-color: rgba(0,0,0,0.12)
}
/ Reset básico (opcional) /
.site-header{
box-sizing: border-box
}
/ Cabecera pegada /
.site-header{
position: fixed
top: 0
left: 0
right: 0
height: var(--header-height)
background: var(--header-bg)
z-index: var(--header-z)
display: flex
align-items: center
transition: box-shadow 220ms ease, background-color 220ms ease, transform 200ms ease
box-shadow: none / sin sombra en el tope /
-webkit-backdrop-filter: saturate(110%) blur(4px) / opcional, solo en navegadores compatibles /
backdrop-filter: saturate(110%) blur(4px)
}
/ Para que el contenido no quede debajo de la cabecera (evitar salto) /
html {
/ Si tu tema añade padding o margin al body, mejor añadir el margen en el main container.
Aquí se muestra el concepto: puedes añadir padding-top al .site-content en lugar de html/body. /
}
body {
padding-top: var(--header-height)
}
/ Sombra que aparece al hacer scroll (clase activada por JS) /
.site-header.is-scrolled{
box-shadow: 0 6px 18px -8px var(--shadow-color)
background: rgba(255,255,255,0.96)
}
/ Variante: sombra más sutil cuando no hay fondo blanco /
.site-header.transparent{
background: transparent
}
/ Ajustes responsivos: ejemplo /
@media (max-width: 768px){
:root{ --header-height: 56px }
.site-header{ height: var(--header-height) }
}
Notas CSS importantes
- Asegúrate de que la variable –header-height refleje la altura real de la cabecera. Si tu cabecera tiene altura dinámica, usa un valor fijo o calcula el padding-top con JS al cargar.
- Evita usar top: 0 en combinación con transform translateY para animaciones, salvo que quieras animar la cabecera fuera de la pantalla.
- La propiedad backdrop-filter mejora apariencia en cabeceras semitransparentes pero no es soportada en todos los navegadores—no depende de la funcionalidad de la sombra.
JavaScript (detectar scroll y alternar clase)
Un script ligero que comprueba si el usuario ha hecho scroll hacia abajo y, si es así, añade la clase .is-scrolled a la cabecera. Lleva una pequeña mejora de rendimiento usando requestAnimationFrame para evitar recálculos excesivos en scroll rápido.
(function(){
var doc = document
var header = doc.querySelector(.site-header)
if(!header) return
var lastKnownScrollY = 0
var ticking = false
var threshold = 6 // píxeles mínimos para activar (evita parpadeos en micro-scrolls)
function onScroll() {
lastKnownScrollY = window.scrollY window.pageYOffset
requestTick()
}
function requestTick() {
if(!ticking) {
requestAnimationFrame(update)
}
ticking = true
}
function update() {
ticking = false
var y = lastKnownScrollY
if(y > threshold){
if(!header.classList.contains(is-scrolled)){
header.classList.add(is-scrolled)
}
} else {
if(header.classList.contains(is-scrolled)){
header.classList.remove(is-scrolled)
}
}
}
window.addEventListener(scroll, onScroll, {passive:true})
// Ejecutar una vez al cargar para cubrir el caso de reload en mitad de página
update()
})()
Mejoras opcionales al JS
- Si quieres que la cabecera desaparezca al bajar y aparezca al subir, añade lógica comparando la posición actual con la anterior para aplicar clases is-hidden / is-visible.
- Si tu cabecera tiene altura dinámica, calcula la altura con header.getBoundingClientRect().height y aplica padding-top al contenedor principal en vez de usar una variable CSS fija.
Alternativa: CSS puro con :has() (experimental)
Si prefieres no usar JavaScript, existe una técnica que coloca un sentinel (un elemento vacío justo después del header) y usa :has() y :not() para detectar si el sentinel está intersectando. Esto funciona sólo en navegadores que soportan :has() y comportamientos específicos comprobar compatibilidad antes de usar en producción.
/ Estructura requerida:
ltheader class=site-headergt...lt/headergt
ltdiv class=header-sentinelgtlt/divgt
.header-sentinel debe estar pegado justo después del header en el DOM.
/
.header-sentinel{
height: 1px
margin-top: calc(-1px) / pegado visualmente al final del header /
}
/ Si el header no toca el tope (es decir, el sentinel ha salido del view), se aplica la sombra /
.site-header:has( .header-sentinel:not(:root:where(:root))){
/ Esta regla es conceptual. La especificidad y el selector exacto
pueden variar y su compatibilidad es limitada. /
box-shadow: 0 6px 18px -8px rgba(0,0,0,0.12)
}
Importante: :has() todavía no está soportado en todos los navegadores (ver soporte actual). Por compatibilidad, la solución con JavaScript es la más robusta.
Integración en WordPress (enqueue de estilos y scripts)
Para añadir el CSS y JS correctamente en WordPress sin editar archivos directamente del núcleo, usa functions.php de tu tema (o mejor, un plugin de funcionalidad). Ejemplo de cómo encolar los archivos:
function mi_tema_enqueue_sticky_header(){
// CSS principal del tema (ya suele estar encolado). Aquí se añade un archivo adicional si hace falta.
wp_enqueue_style(
mi-sticky-header-css,
get_stylesheet_directory_uri() . /assets/css/sticky-header.css,
array(),
1.0
)
// JS ligero para alternar la clase.
wp_enqueue_script(
mi-sticky-header-js,
get_stylesheet_directory_uri() . /assets/js/sticky-header.js,
array(),
1.0,
true
)
}
add_action(wp_enqueue_scripts, mi_tema_enqueue_sticky_header)
Coloca el CSS del ejemplo en assets/css/sticky-header.css y el JS en assets/js/sticky-header.js (o integra en tus archivos existentes). Al usar el último parámetro en wp_enqueue_script como true, el script se carga en el footer para no bloquear el render inicial.
Optimización y buenas prácticas
- Usa passive: true en addEventListener(scroll) para mejorar la respuesta del scroll en móviles.
- Reduce el trabajo en cada evento de scroll el ejemplo usa requestAnimationFrame para agrupar actualizaciones y evitar layout thrashing.
- Evita reflow costoso dentro del handler (por ejemplo, no leer y escribir propiedades que fuerzan layout repetidamente).
- Si tu tema usa un constructor o framework, adapta las clases y la integración para respetar su estructura (ej.: Elementor, Divi, etc.).
- Prueba en dispositivos móviles y navegadores donde la barra de dirección puede cambiar el viewport height (scrollY puede fluctuar) la lógica con umbral evita parpadeos.
Accesibilidad y UX
- Si ocultas la cabecera al bajar (comportamiento adicional), asegúrate de que siga siendo accesible con teclado y que no dificulte la navegación.
- Evita animaciones demasiado rápidas o bruscas usa transiciones suaves y evita saltos de contenido.
- Comprueba que la relación de contraste de la cabecera con su fondo sea adecuada cuando la sombra aparece o el fondo cambia a semitransparente.
Recapitulación final
Resumen rápido de pasos para implementar la cabecera pegada con sombra condicional:
- Marcar la cabecera con una clase clara (.site-header) y asegurarte de que el HTML del tema lo use.
- Aplicar CSS para fijar la cabecera, definir la transición y la sombra cuando esté la clase .is-scrolled.
- Agregar un pequeño script que detecte el scroll y añada/quite la clase .is-scrolled usando requestAnimationFrame para eficiencia.
- Encolar correctamente los archivos CSS/JS en WordPress mediante functions.php.
Ejemplo completo — ubicación sugerida de archivos
- assets/css/sticky-header.css — (pegar el bloque CSS anterior)
- assets/js/sticky-header.js — (pegar el bloque JS anterior)
- header.php — asegurar la estructura HTML mostrada
- functions.php — encolar los archivos con el ejemplo PHP
Observación final
La combinación CSS un JS mínimo ofrece la mayor compatibilidad y control. Si necesitas que el comportamiento sea completamente sin JS, revisa el método con :has() pero ten en cuenta las limitaciones de soporte. Ajusta las variables CSS y la lógica de umbral para adaptarlo a tu diseño y experiencia deseada.
Leave a Reply