Acordeón sin JS (FAQ)
Componente de acordeón accesible para secciones de preguntas frecuentes (FAQ), construido nativamente con <details> y <summary> en HTML5 y CSS.
Aprovechando el poder de las etiquetas semánticas <details> y <summary> de HTML5, es posible construir un componente de acordeón completamente funcional sin una sola línea de JavaScript. Este enfoque es excelente para el SEO y garantiza accesibilidad (a11y) nativa, incluyendo la navegación por teclado.
Demo
¿Cuáles son las características de este acordeón?
Está construido únicamente con funciones estándar de HTML y CSS, sin usar JavaScript. Es muy ligero y también excelente para el SEO y la accesibilidad (como el soporte para la operación por teclado).
¿Puedo abrir varios elementos al mismo tiempo?
Al establecer el atributo name con el mismo valor (en este ejemplo name=“faq”), puedes tener un control exclusivo donde al abrir uno se cierran automáticamente los demás. Si deseas permitir que se abran simultáneamente, elimina el atributo name.
¿Cómo se implementa la animación?
La animación de rotación del icono y el efecto de desvanecimiento del contenido se implementan utilizando transition y @keyframes de CSS.
Código
<div class="accordion-container">
<details class="accordion" name="faq">
<summary class="accordion-summary">
¿Cuáles son las características de este acordeón?
<span class="icon"></span>
</summary>
<div class="accordion-content">
<p>Está construido únicamente con funciones estándar de HTML y CSS, sin usar JavaScript. Es muy ligero y también excelente para el SEO y la accesibilidad (como el soporte para la operación por teclado).</p>
</div>
</details>
<details class="accordion" name="faq">
<summary class="accordion-summary">
¿Puedo abrir varios elementos al mismo tiempo?
<span class="icon"></span>
</summary>
<div class="accordion-content">
<p>Al establecer el atributo name con el mismo valor, se habilita el control exclusivo (al abrir uno, los demás se cierran).</p>
</div>
</details>
</div>/* Estilo del contenedor */
.accordion-container {
display: flex;
flex-direction: column;
gap: 1rem;
width: 100%;
max-width: 600px;
margin: 0 auto;
}
/* Cuerpo del acordeón */
.accordion {
border: 1px solid #e2e8f0;
border-radius: 8px;
background-color: #ffffff;
overflow: hidden;
box-shadow: 0 1px 3px rgba(0,0,0,0.05);
}
/* Estilo del resumen (título) */
.accordion-summary {
padding: 1.25rem 1.5rem;
font-weight: 600;
font-size: 1.05rem;
cursor: pointer;
display: flex;
justify-content: space-between;
align-items: center;
list-style: none; /* Ocultar el marcador triangular predeterminado */
color: #1e293b;
transition: background-color 0.2s ease;
user-select: none;
}
/* Ocultar el marcador triangular predeterminado para Safari */
.accordion-summary::-webkit-details-marker {
display: none;
}
.accordion-summary:hover {
background-color: #f8fafc;
}
/* Subrayado del resumen en estado abierto */
.accordion[open] .accordion-summary {
border-bottom: 1px solid #e2e8f0;
}
/* Estilo del icono de abrir/cerrar */
.icon {
position: relative;
width: 20px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
margin-left: 1rem;
}
/* Líneas horizontales y verticales del icono */
.icon::before,
.icon::after {
content: '';
position: absolute;
background-color: #64748b;
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
border-radius: 2px;
}
.icon::before {
width: 16px;
height: 2px;
}
.icon::after {
width: 2px;
height: 16px;
}
/* Animación al abrir el acordeón (+ se vuelve -) */
.accordion[open] .icon::after {
transform: rotate(90deg) scaleY(0);
}
.accordion[open] .icon::before {
background-color: #3b82f6;
}
/* Estilo de la parte de contenido */
.accordion-content {
padding: 1.5rem;
color: #475569;
line-height: 1.6;
animation: fadeDown 0.3s ease-out forwards;
}
.accordion-content p {
margin: 0;
}
/* Animación de aparición suave */
@keyframes fadeDown {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
} Puntos de Implementación
- Poder nativo de
<details>y<summary>: El navegador maneja de forma nativa los eventos de clic y el estado (abierto/cerrado), eliminando la necesidad de gestionar el estado del DOM con JavaScript. - Ocultar la flecha por defecto:
Mediante el uso de
list-style: none;y el pseudoelemento::-webkit-details-marker { display: none; }, suprimimos el feo triángulo predeterminado del navegador, abriendo paso para implementar nuestro propio icono personalizado. - Acordeón exclusivo mediante el atributo
name: Agrupando múltiples elementos<details>bajo un mismo atributoname, activamos el comportamiento de “acordeón exclusivo” (al abrir un panel, los otros se colapsan automáticamente). Esta es una especificación de HTML bastante reciente y muy útil. - Animaciones CSS pulidas:
El efecto de revelado suave del contenido (usando
@keyframes) y la rotación fluida del icono de+a-(usandotransition) elevan la experiencia del usuario de manera sencilla, confiando exclusivamente en el motor CSS.