Tutorial WordPress: Diseñar un layout de preguntas frecuentes tipo acordeón con detalles/summary

·

·

Introducción

Este tutorial explica paso a paso cómo diseñar un layout de preguntas frecuentes (FAQ) tipo acordeón usando las etiquetas semánticas ltdetailsgt y ltsummarygt, y cómo integrarlo correctamente en un sitio WordPress. Cubriremos la estructura HTML, el CSS para un aspecto moderno, mejoras con JavaScript (animación, comportamiento de abrir/cerrar, accesibilidad y navegación por teclado) y la forma recomendada de insertar el bloque en WordPress mediante un shortcode y el correcto registro/encolado de estilos y scripts. Todos los ejemplos de código se incluyen listos para copiar y pegar.

Por qué usar details/summary

Estructura HTML básica

Ejemplo mínimo de un elemento FAQ con details/summary:

ltdetailsgt
  ltsummarygt¿Cómo puedo crear una cuenta?lt/summarygt
  ltpgtPara crear una cuenta, haz clic en lta href=#gtRegistrolt/agt y completa el formulario.lt/pgt
lt/detailsgt

Para varias preguntas, se repite el bloque ltdetailsgt:

ltsection class=faqgt
  ltdetailsgt
    ltsummarygt¿Cómo puedo crear una cuenta?lt/summarygt
    ltpgtPara crear una cuenta, haz clic en lta href=#gtRegistrolt/agt y completa el formulario.lt/pgt
  lt/detailsgt

  ltdetailsgt
    ltsummarygt¿Cómo restablezco mi contraseña?lt/summarygt
    ltpgtUsa la opción quot¿Olvidaste tu contraseña?quot en la pantalla de acceso.lt/pgt
  lt/detailsgt
lt/sectiongt

Estilos CSS recomendados

Objetivos del CSS: apariencia de acordeón, iconos, transiciones suaves, respetar prefers-reduced-motion y estilos de foco accesibles.

/ Estilos base para la FAQ /
.faq {
  max-width: 800px
  margin: 0 auto
  font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica Neue, Arial
}

/ Resetea el estilo por defecto del summary /
.faq summary {
  list-style: none
  cursor: pointer
  display: flex
  align-items: center
  justify-content: space-between
  padding: 1rem
  background: #f7f7f8
  border: 1px solid #e3e3e6
  border-radius: 6px
  margin-top: 0.8rem
  font-weight: 600
  transition: background .15s ease
  outline: none
}

/ Indicador (flecha) con pseudo-elemento /
.faq summary::marker { display: none } / evita marcador por defecto /
.faq summary::after {
  content: 
  width: 1rem
  height: 1rem
  transform: rotate(0deg)
  transition: transform .18s ease
  mask: url(data:image/svg xmlutf8,ltsvg xmlns=http://www.w3.org/2000/svg viewBox=0 0 24 24gtltpath fill=black d=M7 10l5 5 5-5z/gtlt/svggt) center / contain no-repeat
  background-color: #333
  margin-left: 1rem
}

/ Estado abierto: gira la flecha /
.faq details[open] summary::after {
  transform: rotate(180deg)
}

/ Contenedor del contenido oculto /
.faq details > p {
  margin: 0
  padding: 1rem
  border: 1px solid #e3e3e6
  border-top: none
  background: #fff
  line-height: 1.6
}

/ Foco accesible /
.faq summary:focus {
  box-shadow: 0 0 0 3px rgba(50,115,220,0.15)
}

/ Reducir animaciones si el usuario lo solicita /
@media (prefers-reduced-motion: reduce) {
  .faq summary,
  .faq summary::after {
    transition: none
  }
}

Animación suave de apertura (JS)

Por defecto el elemento ltdetailsgt abre/cierra sin animación transversal. Para animarlo con altura dinámica se puede usar JavaScript que calcule la altura del contenido. El siguiente script añade animación y opcionalmente fuerza que solo uno esté abierto a la vez (comportamiento accordion).

/ Animación para details: slide-down/slide-up y control de un solo abierto /
document.addEventListener(DOMContentLoaded, function () {
  const detailsList = document.querySelectorAll(.faq details)

  detailsList.forEach(details =gt {
    const summary = details.querySelector(summary)
    const content = Array.from(details.childNodes).filter(n =gt n.nodeType === 1  n.tagName.toLowerCase() !== summary)[0]

    // Para animar, guardamos la altura cuando está abierto
    details.addEventListener(toggle, (e) =gt {
      if (details.open) {
        // Si queremos un solo abierto a la vez:
        detailsList.forEach(other =gt {
          if (other !== details) other.open = false
        })
        content.style.display = block
        const h = content.getBoundingClientRect().height
        content.style.height = 0px
        // Forzar repaint
        content.offsetHeight
        content.style.transition = height 220ms ease
        content.style.height = h   px
        content.addEventListener(transitionend, function te() {
          content.style.height = 
          content.style.transition = 
          content.removeEventListener(transitionend, te)
        })
      } else {
        const h = content.getBoundingClientRect().height
        content.style.height = h   px
        // Forzar repaint
        content.offsetHeight
        content.style.transition = height 180ms ease
        content.style.height = 0px
        content.addEventListener(transitionend, function tc() {
          content.style.display = 
          content.style.height = 
          content.style.transition = 
          content.removeEventListener(transitionend, tc)
        })
      }
    })
  })
})

Notas importantes sobre el script

Accesibilidad y navegación por teclado

Detalles clave para que una FAQ sea accesible:

  1. El elemento ltsummarygt ya es focusable y responde a Enter/Space. Mantén estilos de foco claros.
  2. Evita usar roles ARIA adicionales por defecto details/summary ya proveen semántica. Si añades roles, asegúrate de no introducir contradicciones.
  3. Si aplicas animaciones, respetar prefers-reduced-motion para usuarios que soliciten menos movimiento.
  4. Si creas un componente complejo que oculta/gestiona estados manualmente (sin details), implementa roles ARIA apropiados y manejo de teclado (Up/Down para navegar entre sumarios, Home/End para ir a inicio/fin, etc.).

Integración en WordPress: Shortcode Enqueue

A continuación un ejemplo de cómo registrar un shortcode que renderice una lista de FAQs, y cómo encolar los estilos y scripts desde functions.php.

/ functions.php (o un plugin propio) /

/ Encolado de estilos y scripts /
function mi_faq_enqueue_assets() {
  wp_enqueue_style( mi-faq-style, get_stylesheet_directory_uri() . /assets/mi-faq.css, array(), 1.0.0 )
  wp_enqueue_script( mi-faq-script, get_stylesheet_directory_uri() . /assets/mi-faq.js, array(), 1.0.0, true )
}
add_action( wp_enqueue_scripts, mi_faq_enqueue_assets )

/ Shortcode [mi_faq] que acepta contenido en formato simple (puedes adaptar a ACF o bloques) /
function mi_faq_shortcode( atts = array(), content = null ) {
  // Ejemplo simple: parseamos un contenido con separador
  // Uso: [mi_faq]Pregunta 1::Respuesta 1Pregunta 2::Respuesta 2[/mi_faq]
  raw = do_shortcode( content )
  items = array_filter( array_map( trim, explode(, raw) ) )
  output = 
foreach ( items as item ) { list( q, a ) = array_map( trim, explode(::, item . ::) ) output .=
output .= . wp_kses_post( q ) . output .=
. wp_kses_post( wpautop( a ) ) .
output .=
} output .=
return output } add_shortcode( mi_faq, mi_faq_shortcode )

Explicación breve:

Ejemplo completo de CSS y JS listo para WordPress

CSS (guardar en assets/mi-faq.css):

/ Contenido similar al ejemplo anterior, adaptado al selector .faq /
.faq { max-width: 900px margin: 1.5rem auto font-family: sans-serif }
.faq summary { ... } / Usa el CSS del bloque anterior tal cual /

JS (guardar en assets/mi-faq.js):

/ Copia el script de animación mostrado anteriormente /
document.addEventListener(DOMContentLoaded, function () {
  // código de animación y control de un solo abierto
})

Uso práctico en una entrada o página

Ejemplo de uso del shortcode dentro del editor de WordPress (editor clásico o bloque shortcode):

[mi_faq]¿Cómo creo una cuenta?::Ve a Registro y completa el formulario.¿Cómo contacto soporte?::Usa el formulario en la página de contacto.[/mi_faq]

Variantes y mejoras avanzadas

Pruebas y depuración

  1. Prueba sin JavaScript para asegurarte de que details/summary permiten acceder a todo el contenido.
  2. Comprueba comportamiento en móviles y teclados: Tab para foco, Enter/Space para abrir, y lectores de pantalla.
  3. Verifica que los assets estén correctamente encolados y que no haya conflicto con otros scripts del tema o plugins.
  4. Revisa la política de caché/optimización (minificación, concatenación) de tu sitio para evitar que el script no cargue o se ejecute fuera de orden.

Conclusión

Usar ltdetailsgt y ltsummarygt te da una base semántica y accesible para construir FAQs tipo acordeón. Añadiendo CSS y una capa leve de JavaScript obtendrás una experiencia moderna con animaciones y control de estado. En WordPress lo más sencillo es exponer el conjunto mediante un shortcode o un bloque, y encolar correctamente los assets. Siguiendo las prácticas de accesibilidad (foco visible, respects prefers-reduced-motion, no eliminar funcionalidad sin JS) tendrás un componente robusto y usable para tu sitio.

Enlaces útiles



Leave a Reply

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