Tutorial WordPress: Crear una cabecera con degradado dinámico usando CSS

·

·

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

Preparación y archivos a tocar

  1. header.php (o template-parts del tema): marcar la estructura de la cabecera y colocar la imagen destacada si procede.
  2. style.css (o archivo SCSS compilado): declarar variables por defecto, estilos de la cabecera, fallback sin JS y consideraciones responsive.
  3. js/gradient-header.js: script que calcula y aplica los colores dinámicos.
  4. 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):

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

Variantes y mejoras posibles

Errores comunes y cómo resolverlos

  1. El script no se carga: comprueba la ruta en wp_enqueue_script y la existencia del archivo. Revisa consola por 404 o errores JS.
  2. 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.
  3. 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.
  4. 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

Your email address will not be published. Required fields are marked *