Introducción
En este tutorial completo aprenderás a crear una cabecera en WordPress que muestre una sombra (box-shadow) únicamente cuando el usuario hace scroll. La técnica combina HTML/PHP (para integrar en tu tema), estilos CSS para la apariencia y JavaScript eficiente para añadir/quitar la clase que activa la sombra. Incluyo varias alternativas (scroll event con requestAnimationFrame, IntersectionObserver), cómo cargar los archivos correctamente desde functions.php y consejos de optimización y compatibilidad.
Qué conseguirás
- Una cabecera fija o sticky que mantiene su posición en la parte superior.
- Una sombra visible solo cuando la página está desplazada hacia abajo (no en el topo inicial).
- Código listo para integrar en un tema hijo o en un plugin pequeño.
Requisitos previos
- Conocimientos básicos de WordPress (editar header.php y functions.php o crear un plugin pequeño).
- Acceso FTP o editor de temas desde el panel de WP.
- Preferible usar un tema hijo para no perder cambios con actualizaciones.
1. Estructura HTML / PHP de la cabecera
La mayoría de temas usan header.php para la cabecera. Aquí tienes un fragmento típico. Inserta o adapta según tu tema. La idea es que el elemento principal tenga una clase identificable, por ejemplo .site-header o #site-header.
ltheader id=site-header class=site-headergt
ltdiv class=site-header-innergt
lt!-- logo, navegación, botones, etc. --gt
lta class=site-logo href=lt?php echo esc_url( home_url(/) ) ?gtgtMi weblt/agt
ltnav class=main-navigationgt
lt?php wp_nav_menu( array( theme_location =gt primary ) ) ?gt
lt/navgt
lt/divgt
lt/headergt
Si tu cabecera ya está en el tema, solo asegúrate de que el elemento raíz tenga un identificador o una clase estable, por ejemplo #site-header o .site-header.
2. CSS base: posición y la sombra activable
Define estilos básicos: posición sticky o fixed, altura, z-index y la transición de la sombra. La clase .has-shadow se añadirá con JavaScript al hacer scroll para activar el box-shadow.
/ Ajusta variables a tu diseño /
:root {
--header-bg: #ffffff
--header-height: 72px
--header-z: 999
--shadow-color: rgba(0,0,0,0.12)
--shadow-y: 6px
--shadow-blur: 18px
--transition-time: 200ms
}
/ Cabecera fija en top (puedes usar position: sticky si lo prefieres) /
.site-header {
position: fixed / o sticky /
top: 0
left: 0
right: 0
height: var(--header-height)
background: var(--header-bg)
z-index: var(--header-z)
transition: box-shadow var(--transition-time) ease, background var(--transition-time) ease
-webkit-backface-visibility: hidden / suaviza transformaciones /
}
/ Evitar que el contenido suba debajo de la cabecera: añade padding-top al body o al contenedor principal /
body.has-fixed-header .site-content {
padding-top: var(--header-height)
}
/ Sombra visible sólo cuando se añade la clase /
.site-header.has-shadow {
box-shadow: 0 var(--shadow-y) var(--shadow-blur) var(--shadow-color)
}
/ Pequeñas mejoras responsive /
@media (max-width: 768px) {
:root { --header-height: 64px }
}
Notas: si tu tema ya aplica padding-top con un placeholder para cabecera sticky, adapta el selector body.has-fixed-header .site-content o usa otra clase/selector adecuado.
3. JavaScript eficiente para añadir la clase al hacer scroll
Evita listeners costosos en scroll sin moderación. A continuación dos enfoques recomendados:
3.1 Enfoque simple y robusto con requestAnimationFrame (compatible ampliamente)
Este script detecta si la página está en la posición top (offset 0) o está desplazada y añade/quita la clase has-shadow en la cabecera. Usa requestAnimationFrame para limitar repintados.
(function() {
var header = document.getElementById(site-header) document.querySelector(.site-header)
if (!header) return
var lastY = window.scrollY
var ticking = false
var threshold = 4 // px: para evitar micro-fluctuaciones
function onScroll() {
lastY = window.scrollY window.pageYOffset
if (!ticking) {
window.requestAnimationFrame(function() {
updateHeaderShadow(lastY)
ticking = false
})
ticking = true
}
}
function updateHeaderShadow(scrollY) {
if (scrollY > threshold) {
if (!header.classList.contains(has-shadow)) header.classList.add(has-shadow)
document.documentElement.classList.add(has-scrolled) // opcional
} else {
header.classList.remove(has-shadow)
document.documentElement.classList.remove(has-scrolled)
}
}
window.addEventListener(scroll, onScroll, { passive: true })
// Ejecutar una vez al cargar para estado inicial (por ejemplo reload en medio de la página)
updateHeaderShadow(window.scrollY window.pageYOffset)
})()
3.2 Alternativa moderna: IntersectionObserver
En vez de escuchar scroll constantemente, colocas un sentinel justo después del header o al inicio del contenido y observas cuando sale del viewport. Muy eficiente y claro conceptualmente.
(function() {
var header = document.getElementById(site-header) document.querySelector(.site-header)
if (!header) return
/ Inserta en tu template un div sentinel justo después del header:
ltdiv id=header-sentinel style=position: absolute top: var(--header-height) height: 1px width: 1pxgtlt/divgt
O crea dinámicamente: /
var sentinel = document.getElementById(header-sentinel)
if (!sentinel) {
sentinel = document.createElement(div)
sentinel.id = header-sentinel
sentinel.style.position = absolute
sentinel.style.top = (header.offsetHeight 0) px
sentinel.style.width = 1px
sentinel.style.height = 1px
// Añadir al DOM después del header
header.parentNode.insertBefore(sentinel, header.nextSibling)
}
if (IntersectionObserver in window) {
var io = new IntersectionObserver(function(entries) {
entries.forEach(function(entry) {
if (!entry.isIntersecting) {
header.classList.add(has-shadow)
} else {
header.classList.remove(has-shadow)
}
})
}, { root: null, threshold: [0] })
io.observe(sentinel)
} else {
// Fallback al método rAF si no hay IO
var lastY = window.scrollY
window.addEventListener(scroll, function() {
window.requestAnimationFrame(function() {
if (window.scrollY > 4) header.classList.add(has-shadow)
else header.classList.remove(has-shadow)
})
}, { passive: true })
}
})()
4. Cómo añadir los scripts y estilos correctamente en functions.php
No pongas JavaScript directamente en header.php sin encolarlo la forma correcta es usar wp_enqueue_script y wp_enqueue_style para evitar conflictos y facilitar cacheo. Añade este código en functions.php de tu tema (idealmente tema hijo).
/ functions.php /
function tema_hijo_enqueue_header_shadow() {
// CSS (puede estar en tu style.css o archivo separado)
wp_enqueue_style( tema-header-shadow, get_stylesheet_directory_uri() . /css/header-shadow.css, array(), 1.0 )
// JS: crea un archivo JS en tu tema hijo, por ejemplo js/header-shadow.js
wp_enqueue_script( tema-header-shadow-js, get_stylesheet_directory_uri() . /js/header-shadow.js, array(), 1.0, true )
// Si necesitas pasar datos PHP a JS:
wp_localize_script( tema-header-shadow-js, HeaderShadowVars, array(
threshold => 4,
) )
}
add_action( wp_enqueue_scripts, tema_hijo_enqueue_header_shadow )
Alternativa: si prefieres inyectar pequeñas porciones de JS inline (no recomendado para grandes scripts), usa wp_add_inline_script sobre un script ya encolado.
5. Manejo del admin bar y otros detalles
- Admin bar (usuarios logueados): WordPress añade 32px de altura. Ajusta top si usas position: fixed o añade CSS condicional: body.admin-bar .site-header { top: 32px }
- Compatibilidad con sticky: Si usas position: sticky, el comportamiento es similar, pero asegúrate de que el contenedor no tenga overflow oculto que impida sticky.
- Placeholder para evitar layout shift: Si tu header es fixed, añade padding-top en el contenedor principal igual a la altura del header para que no se superponga el contenido.
- Soporte RTL: La sombra funciona igual sólo revisa menús y alineaciones.
6. Personalización de la sombra
Puedes modificar variables CSS para ajustar color, desplazamiento y difuminado. Ejemplos rápidos:
/ Sombra sutil / --shadow-color: rgba(0,0,0,0.08) --shadow-y: 4px --shadow-blur: 10px / Sombra pronunciada / --shadow-color: rgba(0,0,0,0.18) --shadow-y: 10px --shadow-blur: 30px
También puedes animar la opacidad para un efecto más suave o añadir una línea inferior en lugar de box-shadow usando ::after y transiciones.
7. Pruebas y depuración
- Comprueba la carga del CSS y JS en el inspector de red (DevTools).
- Verifica que el selector de la cabecera coincide con el usado en el script (ID o clase).
- Recarga la página con cache desactivada o versiona los archivos (cambia el parámetro de versión en wp_enqueue_).
- Activa logs JS en consola: console.log dentro del observer o función de rAF para comprobar que se ejecuta.
- Prueba en móvil y tablet ajusta threshold y altura de cabecera para evitar saltos no deseados.
8. Posibles errores comunes y soluciones
- La clase no se añade: Verifica que el selector usado en document.getElementById o querySelector realmente exista y no sea dinamicamente reemplazado por el theme builder.
- Layout shift al fijar cabecera: Añade padding-top al contenedor principal equivalente a la altura del header.
- Problemas con admin-bar: Añade CSS para body.admin-bar .site-header { top: 32px } o calcula dinámicamente en JS.
- Rendimiento pobre: Usa requestAnimationFrame o IntersectionObserver y listeners passive: true para scroll.
9. Versión mínima (todo en un snippet) para pruebas rápidas
Si quieres probar rápidamente en un tema de desarrollo, coloca este CSS y JS en los archivos correspondientes. Recuerda mover al functions.php para una integración correcta en producción.
/ quick demo CSS (colocar en header-shadow.css) /
.site-header {
position: fixed
top: 0
left: 0
right: 0
height: 64px
background: #fff
transition: box-shadow 180ms ease
z-index: 9999
}
.site-header.has-shadow {
box-shadow: 0 8px 24px rgba(0,0,0,0.12)
}
body { margin: 0 }
.site-content { padding-top: 64px } / evitar que el contenido quede bajo la cabecera /
/ quick demo JS (colocar en js/header-shadow.js) /
(function() {
var header = document.querySelector(.site-header)
if (!header) return
function update() {
if (window.pageYOffset > 4) header.classList.add(has-shadow)
else header.classList.remove(has-shadow)
}
window.addEventListener(scroll, update, { passive: true })
update()
})()
10. Resumen final y recomendaciones
Crear una cabecera con sombra al hacer scroll es una mejora visual sencilla que aporta profundidad y legibilidad. Las mejores prácticas son:
- Usar clases para activar la sombra (.has-shadow) y transiciones CSS para suavidad.
- Evitar listeners de scroll costosos: preferir requestAnimationFrame o IntersectionObserver.
- Encolar correctamente scripts y estilos con wp_enqueue_.
- Considerar el admin bar y agregar placeholder para evitar saltos de contenido.
Implementa los fragmentos proporcionados en tu tema hijo, ajusta variables CSS a tu diseño y prueba en distintos dispositivos. Fin del tutorial.
Leave a Reply