Este tutorial explica paso a paso cómo crear una cabecera (header) con un degradado dinámico en WordPress usando CSS moderno, variables CSS y un poco de JavaScript para actualizar los colores en tiempo real. El objetivo es obtener una cabecera visualmente atractiva que pueda cambiar según la hora del día, el desplazamiento (scroll) o incluso tomando colores de la imagen destacada (featured image) de la entrada. Incluye buenas prácticas para rendimiento, accesibilidad y compatibilidad.
Resumen del enfoque
- Estructura HTML: una cabecera con una capa de imagen (opcional) y contenido encima.
- Estilos: uso de variables CSS (–g1, –g2, etc.) para controlar los colores del degradado y transiciones suaves.
- JavaScript: actualizar las variables CSS según reglas (hora, scroll o color promedio de la imagen).
- Integración en WordPress: snippets para header.php, functions.php y archivo JS separado para un cargado correcto.
Preparación y archivos a tocar
- header.php (o template-parts del tema): marcar la estructura de la cabecera y colocar la imagen destacada si procede.
- style.css (o archivo SCSS compilado): declarar variables por defecto, estilos de la cabecera, fallback sin JS y consideraciones responsive.
- js/gradient-header.js: script que calcula y aplica los colores dinámicos.
- functions.php: encolar (enqueue) el script y el stylesheet correctamente.
1) Estructura recomendada para header.php
La idea es tener una capa de fondo (imagen opcional) y el bloque de contenido encima. A continuación un ejemplo de cómo sacar la URL de la imagen destacada y renderizarla dentro del header.
ltheader class=site-headergt
lt?php
featured =
if (is_singular() has_post_thumbnail()) {
featured = get_the_post_thumbnail_url(get_the_ID(), full)
} elseif (get_header_image()) {
featured = get_header_image()
}
?gt
lt?php if (featured): ?gt
ltdiv class=header-bg aria-hidden=truegt
ltimg src=lt?php echo esc_url(featured) ?gt alt= /gt
lt/divgt
lt?php endif ?gt
ltdiv class=site-innergt
ltdiv class=site-brandinggt
lth1 class=site-titlegtlta href=lt?php echo esc_url(home_url(/)) ?gtgtlt?php bloginfo(name) ?gtlt/agtlt/h1gt
ltp class=site-descriptiongtlt?php bloginfo(description) ?gtlt/pgt
lt/divgt
lt?php get_template_part(template-parts/navigation/navigation, header) ?gt
lt/divgt
lt/headergt
2) CSS base (variables, degradado y capas)
Definimos variables con valores por defecto para que haya un fallback si JavaScript no carga. Mantenemos las transiciones y respetamos la preferencia de reducir movimiento.
/ Variables por defecto y fallback /
.site-header {
--g1: #0066ff / color inicial /
--g2: #00ccff / color final /
--overlay: rgba(0,0,0,0.3)
position: relative
color: #fff
background: linear-gradient(90deg, var(--g1), var(--g2))
transition: background 400ms ease, color 300ms ease
overflow: hidden
min-height: 280px
display: flex
align-items: center
}
/ Capa de imagen detrás del degradado /
.header-bg {
position: absolute
inset: 0
z-index: 0
overflow: hidden
}
.header-bg img {
width: 100%
height: 100%
object-fit: cover
transform: scale(1.05)
filter: saturate(1.02) contrast(1.02)
}
/ Superposición para mejorar contraste del texto /
.site-header::after {
content:
position: absolute
inset: 0
background: linear-gradient(180deg, var(--overlay), transparent 40%)
z-index: 1
pointer-events: none
}
/ Contenido encima /
.site-header .site-inner {
position: relative
z-index: 2
padding: 2.5rem 1rem
}
/ Preferencias de movimiento /
@media (prefers-reduced-motion: reduce) {
.site-header { transition: none }
}
/ Responsive (ejemplo simple) /
@media (min-width: 768px) {
.site-header { min-height: 360px }
}
3) Script para actualizar variables CSS
El script tiene tres estrategias (se pueden combinar):
- Degradado según la hora del día (mañana/día/tarde/noche).
- Degradado que se mezcla según la posición del scroll.
- Derivar un color promedio de la imagen destacada cargada y usarlo para crear el degradado.
Guarda este archivo como js/gradient-header.js en tu tema (o child theme) y encola desde functions.php.
(function() {
const header = document.querySelector(.site-header)
if (!header) return
function setVars(c1, c2) {
header.style.setProperty(--g1, c1)
header.style.setProperty(--g2, c2)
}
/ 1) Gradiente por hora del día /
function setGradientByTime() {
const h = new Date().getHours()
if (h >= 5 h < 10) { // amanecer
setVars(#FFD89B, #19547B)
} else if (h >= 10 h < 16) { // día
setVars(#6DD5FA, #2980B9)
} else if (h >= 16 h < 20) { // tarde
setVars(#FFB75E, #ED8F03)
} else { // noche
setVars(#2b5876, #4e4376)
}
}
/ Utilidad: mezclar dos colores hex por t (0..1) /
function lerpHex(a, b, t) {
const ah = a.replace(#,), bh = b.replace(#,)
const ar = parseInt(ah.substring(0,2),16), ag = parseInt(ah.substring(2,4),16), ab = parseInt(ah.substring(4,6),16)
const br = parseInt(bh.substring(0,2),16), bg = parseInt(bh.substring(2,4),16), bb = parseInt(bh.substring(4,6),16)
const rr = Math.round(ar (br - ar) t).toString(16).padStart(2,0)
const rg = Math.round(ag (bg - ag) t).toString(16).padStart(2,0)
const rb = Math.round(ab (bb - ab) t).toString(16).padStart(2,0)
return # rr rg rb
}
/ 2) Gradiente que responde al scroll (mezcla entre dos paletas) /
const paletteTop = [#FF7E5F,#FEB47B] // al tope
const paletteBottom = [#00c6ff,#0072ff] // al bajar
function onScroll() {
const docH = document.documentElement.scrollHeight - window.innerHeight
const t = docH > 0 ? Math.min(1, window.scrollY / docH) : 0
const c1 = lerpHex(paletteTop[0], paletteBottom[0], t)
const c2 = lerpHex(paletteTop[1], paletteBottom[1], t)
setVars(c1, c2)
}
/ 3) Obtener color promedio de la imagen (canvas 1x1) /
function getAverageColor(imgEl) {
try {
const canvas = document.createElement(canvas)
canvas.width = canvas.height = 1
const ctx = canvas.getContext(2d)
ctx.drawImage(imgEl, 0, 0, 1, 1)
const d = ctx.getImageData(0,0,1,1).data
return # [d[0], d[1], d[2]].map(n => n.toString(16).padStart(2,0)).join()
} catch (e) {
return null
}
}
/ Intialización: preferir color de imagen, si no, usar hora luego añadir scroll /
function init() {
const img = header.querySelector(.header-bg img)
if (img img.complete) {
const avg = getAverageColor(img)
if (avg) {
// crear un segundo color más oscuro para contraste
const darker = lerpHex(avg, #000000, 0.45)
setVars(avg, darker)
} else {
setGradientByTime()
}
} else if (img) {
img.addEventListener(load, function() {
const avg = getAverageColor(img)
if (avg) {
const darker = lerpHex(avg, #000000, 0.45)
setVars(avg, darker)
} else {
setGradientByTime()
}
})
img.addEventListener(error, setGradientByTime)
} else {
setGradientByTime()
}
// Escuchar scroll con throttling ligero
let ticking = false
window.addEventListener(scroll, function() {
if (!ticking) {
window.requestAnimationFrame(function() {
onScroll()
ticking = false
})
ticking = true
}
}, { passive: true })
// Primera llamada para que el header esté correcto desde el inicio
onScroll()
}
init()
})()
4) Encolar (enqueue) el script y estilos en functions.php
Ejemplo simple para encolar el JavaScript y asegurarte de que se cargue en el pie (footer):
function mytheme_enqueue_gradient_header() {
// Estilos del tema (si no están ya encolados)
wp_enqueue_style(theme-style, get_stylesheet_uri(), array(), filemtime(get_stylesheet_directory() . /style.css))
// Script del degradado (asegúrate de tener js/gradient-header.js)
wp_enqueue_script(
gradient-header,
get_stylesheet_directory_uri() . /js/gradient-header.js,
array(),
filemtime(get_stylesheet_directory() . /js/gradient-header.js),
true
)
}
add_action(wp_enqueue_scripts, mytheme_enqueue_gradient_header)
Consejos de accesibilidad y rendimiento
- Contraste del texto: siempre añade una superposición (overlay) oscura o clara para garantizar lectura del texto sobre la imagen o degradado. Ajusta –overlay según la imagen.
- Reduce movimiento: respeta la media query prefers-reduced-motion para desactivar animaciones en usuarios que lo requieran.
- Evita cálculos pesados en scroll: usa requestAnimationFrame y throttling/ debouncing. No ejecutes operaciones DOM innecesarias dentro del handler.
- Soporte sin JavaScript: define variables CSS por defecto (como en el CSS mostrado) para que haya un degradado estático razonable si JS está deshabilitado.
- Imágenes optimizadas: usa tamaños adecuados (srcset) y formatos modernos (webp) para no penalizar la carga.
Variantes y mejoras posibles
- Paleta avanzada: en lugar de color medio, usa librerías (Color Thief, Vibrant.js) para extraer colores dominantes y generar una paleta más rica.
- Customizer: exponer opciones en el Customizer para que el administrador elija modo (por hora / por imagen / estático) y colores predefinidos.
- Animaciones sutiles: animar gradientes con transformaciones o filtros CSS para darle dinamismo, siempre respetando reduce-motion.
- Modo oscuro: detectar prefers-color-scheme y ajustar overlay / colores para mantener legibilidad.
Errores comunes y cómo resolverlos
- El script no se carga: comprueba la ruta en wp_enqueue_script y la existencia del archivo. Revisa consola por 404 o errores JS.
- getAverageColor devuelve null o error: si la imagen es cross-origin y no permite lectura de canvas, la extracción fallará. Solución: servir imágenes desde el mismo dominio o calcular la paleta en servidor.
- Degradado no cambia con scroll: asegúrate de que el selector .site-header existe y que no haya errores JS previos que detengan la ejecución.
- Texto ilegible: ajustar –overlay o aplicar mix-blend-mode y sombra de texto para mejorar contraste.
Conclusión
Con unas pocas variables CSS, un bloque de estilos ordenado y un script ligero puedes obtener una cabecera con degradado dinámico que mejora la estética de tu sitio WordPress sin sacrificar rendimiento ni accesibilidad. Implementa las tres estrategias (hora, scroll, colores de imagen) según tus necesidades y proporciona opciones en el theme customizer si quieres que los administradores controlen el comportamiento desde el panel.
Leave a Reply