Tutorial WordPress: Cómo crear un menú hamburguesa accesible con base CSS (sin JS mínimo)

·

·

Introducción

Este tutorial muestra cómo crear un menú hamburguesa accesible usando principalmente CSS, con una mejora opcional mínima en JavaScript para sincronizar atributos ARIA y mejorar la experiencia con teclado y lectores de pantalla. El objetivo es un patrón reutilizable para temas de WordPress: simple, responsivo, accesible y fácil de integrar.

Resumen de la estrategia

Consideraciones de accesibilidad antes de empezar

Estructura HTML recomendada

Ejemplo mínimo de marcado para el menú hamburguesa. Se utiliza un input checkbox (oculto) y un label que sirve de botón. El menú es un ltulgt con enlaces.

lt!-- Contenedor del encabezado / sitio --gt
ltheader class=site-headergt
  ltdiv class=brandgt
    lta href=/ class=logogtMi Sitiolt/agt
  lt/divgt

  lt!-- Checkbox oculto que controla la visibilidad del menú --gt
  ltinput id=menu-toggle class=menu-toggle type=checkbox aria-hidden=true /gt

  lt!-- Label que actúa como botón hamburguesa --gt
  ltlabel for=menu-toggle class=hamburger role=button aria-controls=primary-menu tabindex=0gt
    ltspan class=hamburger-boxgt
      ltspan class=hamburger-innergtlt/spangt
    lt/spangt
    ltspan class=sr-onlygtAbrir menú principallt/spangt
  lt/labelgt

  ltnav id=site-navigation class=main-navigation aria-label=Menú principalgt
    ltul id=primary-menu class=menugt
      ltligtlta href=/categoria-1gtCategoría 1lt/agtlt/ligt
      ltligtlta href=/categoria-2gtCategoría 2lt/agtlt/ligt
      ltligtlta href=/contactogtContactolt/agtlt/ligt
    lt/ulgt
  lt/navgt
lt/headergt

Notas sobre el HTML

CSS: estilos base, hamburguesa y comportamiento responsive

Estilos esenciales: ocultar checkbox, dibujar la hamburguesa, controlar la visibilidad del menú con el selector :checked y asegurar foco visible.

/ Reseteo mínimo /
.menu-toggle { position: absolute left: -9999px }

/ Texto solo para lectores de pantalla /
.sr-only {
  position: absolute !important
  height: 1px width: 1px
  overflow: hidden
  clip: rect(1px, 1px, 1px, 1px)
  white-space: nowrap
}

/ Estilos del botón hamburguesa /
.hamburger {
  display: inline-block
  cursor: pointer
  padding: 0.5rem
  border-radius: 4px
  transition: background .15s
  user-select: none
}
.hamburger:focus {
  outline: 3px solid #0a84ff / foco visible /
  outline-offset: 3px
}

.hamburger-box { display: inline-block width: 30px height: 20px position: relative }
.hamburger-inner,
.hamburger-inner::before,
.hamburger-inner::after {
  display: block
  background-color: #111
  height: 2px
  border-radius: 2px
  position: absolute
  left: 0
  right: 0
  transition: transform .25s ease, opacity .25s ease
}
.hamburger-inner { top: 50% transform: translateY(-50%) }
.hamburger-inner::before { content:  top: -8px }
.hamburger-inner::after  { content:  bottom: -8px }

/ Menú oculto por defecto en pantallas pequeñas /
.main-navigation { display: none }
.main-navigation .menu { list-style: none margin: 0 padding: 0 }
.main-navigation .menu li { margin: 0 }

/ Cuando el checkbox está marcado, mostrar el menú /
.menu-toggle:checked   .hamburger   .main-navigation {
  display: block
}

/ Animación de transformación a X /
.menu-toggle:checked   .hamburger .hamburger-inner {
  transform: rotate(45deg)
}
.menu-toggle:checked   .hamburger .hamburger-inner::before {
  transform: translateY(8px) rotate(90deg)
}
.menu-toggle:checked   .hamburger .hamburger-inner::after {
  opacity: 0
}

/ Responsive: en pantallas grandes mostrar el menú siempre /
@media (min-width: 768px) {
  .hamburger { display: none }
  .main-navigation { display: block !important }
  .main-navigation .menu { display: flex gap: 1rem align-items: center }
}

Explicación del CSS

Mejoras de accesibilidad (JS mínimo opcional)

Con la técnica CSS-only, los atributos ARIA como aria-expanded no se actualizan automáticamente. Para que los lectores de pantalla informen correctamente el estado y para gestionar teclas como Escape, se recomienda un pequeño script que sincronice el estado y gestione el cierre con Escape.

/ Script opcional: sincroniza aria-expanded y cierra con Escape /
document.addEventListener(DOMContentLoaded, function () {
  var toggle = document.getElementById(menu-toggle)
  var label = document.querySelector(label[for=menu-toggle])
  var menu = document.getElementById(primary-menu)

  if (!toggle  !label  !menu) return

  // Inicializar aria-expanded
  label.setAttribute(aria-expanded, toggle.checked ? true : false)

  // Al cambiar el checkbox sincroniza aria-expanded y aria-hidden
  toggle.addEventListener(change, function () {
    label.setAttribute(aria-expanded, toggle.checked ? true : false)
    menu.setAttribute(aria-hidden, toggle.checked ? false : true)
  })

  // Permitir activar el label con Enter/Espacio cuando se enfoca
  label.addEventListener(keydown, function (e) {
    if (e.key === Enter  e.key ===  ) {
      e.preventDefault()
      toggle.checked = !toggle.checked
      toggle.dispatchEvent(new Event(change))
      label.focus()
    }
  })

  // Cerrar con Escape si el menú está abierto
  document.addEventListener(keydown, function (e) {
    if (e.key === Escape  toggle.checked) {
      toggle.checked = false
      toggle.dispatchEvent(new Event(change))
      label.focus()
    }
  })
})

Por qué este JS es útil

Integración en WordPress

Para integrar el HTML en un tema de WordPress puedes registrar la ubicación del menú y renderizarlo con wp_nav_menu(). A continuación un ejemplo simplificado para functions.php y la plantilla del header.

/ functions.php: registrar la ubicación del menú /
function theme_register_menus() {
  register_nav_menus( array(
    primary => Menú Principal,
  ) )
}
add_action( after_setup_theme, theme_register_menus )

/ header.php: implementar el markup (simplificado) /
ltheader class=site-headergt
  ltdiv class=brandgtlta href=/ class=logogtlt?php bloginfo(name) ?gtlt/agtlt/divgt

  ltinput id=menu-toggle class=menu-toggle type=checkbox aria-hidden=true /gt
  ltlabel for=menu-toggle class=hamburger role=button aria-controls=primary-menu tabindex=0gt
    ltspan class=hamburger-boxgtltspan class=hamburger-innergtlt/spangtlt/spangt
    ltspan class=sr-onlygtAbrir menú principallt/spangt
  lt/labelgt

  ltnav id=site-navigation class=main-navigation aria-label=Menú principalgt
    lt?php
      wp_nav_menu( array(
        theme_location => primary,
        menu_id        => primary-menu,
        container      => false,
        items_wrap     => ltul id=%1s class=menugt%3slt/ulgt,
      ) )
    ?gt
  lt/navgt
lt/headergt

Enqueue de estilos y script

En functions.php añade el CSS y, si usas la mejora JS, el script de forma adecuada con dependencias y encolado.

function theme_enqueue_assets() {
  wp_enqueue_style( theme-main, get_stylesheet_uri() )
  wp_enqueue_script( theme-menu, get_template_directory_uri() . /js/menu-accessible.js, array(), 1.0, true )
}
add_action( wp_enqueue_scripts, theme_enqueue_assets )

Pruebas y comprobaciones

  1. Probar navegación por teclado: Tab para llegar al botón, Enter/Espacio para abrir/cerrar, Escape para cerrar (si usas el JS).
  2. Probar con lectores de pantalla (NVDA, VoiceOver, TalkBack): verificar que el control anuncia estado y el menú es navegable.
  3. Comprobación responsive: cambiar ancho de ventana para ver la transición entre menú hamburguesa y menú habitual en desktop.
  4. Accesibilidad visual: contraste y foco visible en el botón y enlaces.
  5. Validar el HTML/CSS y comprobar que la orden del DOM (input label nav) no rompe el layout y funciona con selectores adyacentes.

Resumen y recomendaciones finales

La técnica con checkbox permite construir un menú hamburguesa sin depender de JavaScript, pero para una experiencia plenamente accesible (estado ARIA correcto, mejor manejo del teclado y cierre con Escape) es recomendable añadir un pequeño script. Si prefieres una solución estrictamente semántica, utiliza un ltbuttongt y controla la apertura con JavaScript desde el inicio —esa es la opción más robusta desde el punto de vista de accesibilidad. Integra CSS y JS mediante las funciones de WordPress para mantener compatibilidad con cachés y child themes.

Implementa pruebas reales con usuarios o herramientas de evaluación (axe, Lighthouse, NVDA) y ajusta colores, tamaños de hit area y tiempos de transición para una experiencia óptima.



Leave a Reply

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