Componente FAQ Moderno con Efectos de Cristal
Un componente FAQ moderno con diseño glassmorphism, búsqueda avanzada, modo oscuro y animaciones suaves
Diseño Responsivo
Sí
Soporte para Modo Oscuro
No
líneas
265
Compatibilidad del Navegador
No
Vista Previa en Vivo
Interactúa con el componente sin salir de la página.
Componente FAQ Moderno con Efectos de Cristal
Un componente FAQ moderno y elegante con efectos glassmorphism, búsqueda avanzada, modo oscuro y animaciones suaves.
Características
- 🎨 Diseño Moderno: Efectos glassmorphism y animaciones suaves
- 🔍 Búsqueda Avanzada: Filtrado en tiempo real con resaltado
- 📱 Responsive: Funciona perfectamente en todos los dispositivos
- 🎯 Accesibilidad: Navegación completa por teclado y soporte ARIA
- 🌙 Modo Oscuro: Cambio automático de tema
- 🔖 Marcadores: Guardar preguntas favoritas
- 📊 Analíticas: Seguimiento de eventos integrado
- 🎤 Búsqueda por Voz: Soporte de reconocimiento de voz
- ⚡ Rendimiento: Optimizado para velocidad y eficiencia
Estructura HTML
<div class="modern-faq-container" data-theme="light">
<!-- Elementos de fondo -->
<div class="background-elements">
<div class="floating-shape shape-1"></div>
<div class="floating-shape shape-2"></div>
<div class="floating-shape shape-3"></div>
<div class="gradient-orb orb-1"></div>
<div class="gradient-orb orb-2"></div>
</div>
<!-- Encabezado -->
<header class="faq-header">
<div class="header-content">
<h1 class="main-title">Preguntas Frecuentes</h1>
<p class="subtitle">Encuentra respuestas rápidas a las preguntas más comunes</p>
</div>
<div class="header-controls">
<button class="theme-toggle" aria-label="Cambiar tema">
<i class="fas fa-moon"></i>
</button>
</div>
</header>
<!-- Sección de búsqueda -->
<section class="search-section">
<div class="search-input-wrapper">
<i class="fas fa-search search-icon"></i>
<input
type="text"
class="search-input"
placeholder="Buscar en las preguntas frecuentes..."
aria-label="Buscar preguntas"
>
<button class="voice-search-btn" aria-label="Búsqueda por voz">
<i class="fas fa-microphone"></i>
</button>
<button class="clear-search" aria-label="Limpiar búsqueda">
<i class="fas fa-times"></i>
</button>
</div>
<!-- Sugerencias de búsqueda -->
<div class="search-suggestions" style="display: none;">
<div class="suggestion-item">facturación</div>
<div class="suggestion-item">cuenta</div>
<div class="suggestion-item">contraseña</div>
<div class="suggestion-item">soporte</div>
</div>
<!-- Filtros rápidos -->
<div class="filter-chips">
<button class="filter-chip active" data-filter="all">
<span class="chip-text">Todas</span>
<span class="chip-count">12</span>
</button>
<button class="filter-chip" data-filter="account">
<span class="chip-text">Cuenta</span>
<span class="chip-count">4</span>
</button>
<button class="filter-chip" data-filter="billing">
<span class="chip-text">Facturación</span>
<span class="chip-count">3</span>
</button>
<button class="filter-chip" data-filter="technical">
<span class="chip-text">Técnico</span>
<span class="chip-count">3</span>
</button>
<button class="filter-chip" data-filter="support">
<span class="chip-text">Soporte</span>
<span class="chip-count">2</span>
</button>
</div>
</section>
<!-- Contenido FAQ -->
<main class="faq-content">
<!-- Información de resultados -->
<div class="results-info">
<div class="results-meta">
<span class="results-count">12 resultados</span>
<span class="search-time">(0.003s)</span>
</div>
<div class="view-options">
<button class="view-btn active" data-view="list">
<i class="fas fa-list"></i>
</button>
<button class="view-btn" data-view="grid">
<i class="fas fa-th"></i>
</button>
</div>
</div>
<!-- Elementos FAQ -->
<div class="faq-list">
<!-- Pregunta 1 -->
<article class="faq-item" data-category="account" data-question-id="1">
<div class="faq-item-inner">
<button class="question-button" aria-expanded="false">
<div class="question-content">
<h3 class="question-title">¿Cómo creo una nueva cuenta?</h3>
<div class="question-meta">
<div class="popularity-indicator">
<i class="fas fa-fire"></i>
<span>Popular</span>
</div>
<span class="last-updated">Actualizado hace 2 días</span>
</div>
</div>
<div class="question-actions">
<button class="bookmark-btn" aria-label="Marcar como favorito">
<i class="far fa-bookmark"></i>
</button>
<button class="share-btn" aria-label="Compartir">
<i class="fas fa-share-alt"></i>
</button>
</div>
<div class="expand-indicator">
<i class="fas fa-chevron-down expand-icon"></i>
</div>
</button>
<div class="answer-section" style="max-height: 0; opacity: 0; overflow: hidden; transition: all 0.3s ease;">
<div class="answer-content">
<div class="answer-text">
<p>Crear una nueva cuenta es fácil y solo toma unos minutos. Sigue estos pasos:</p>
<div class="step-list">
<div class="step-item">
<div class="step-number">1</div>
<div class="step-content">
<h4>Visita la página de registro</h4>
<p>Haz clic en el botón "Registrarse" en la esquina superior derecha de nuestra página principal.</p>
</div>
</div>
<div class="step-item">
<div class="step-number">2</div>
<div class="step-content">
<h4>Completa el formulario</h4>
<p>Ingresa tu dirección de correo electrónico, crea una contraseña segura y proporciona tu información básica.</p>
</div>
</div>
<div class="step-item">
<div class="step-number">3</div>
<div class="step-content">
<h4>Verifica tu correo</h4>
<p>Revisa tu bandeja de entrada y haz clic en el enlace de verificación que te enviamos.</p>
</div>
</div>
</div>
<div class="security-note">
<i class="fas fa-shield-alt note-icon"></i>
<div class="note-content">
<strong>Nota de seguridad:</strong> Tu información está protegida con cifrado de nivel bancario y nunca compartimos tus datos personales con terceros.
</div>
</div>
</div>
<div class="answer-footer">
<div class="helpful-section">
<span class="helpful-label">¿Fue útil esta respuesta?</span>
<div class="helpful-buttons">
<button class="helpful-btn helpful-yes">
<i class="fas fa-thumbs-up"></i>
<span>Sí</span>
</button>
<button class="helpful-btn helpful-no">
<i class="fas fa-thumbs-down"></i>
<span>No</span>
</button>
</div>
</div>
<div class="related-links">
<span class="related-label">Ver también:</span>
<a href="#" class="related-link">Verificación de cuenta</a>
<a href="#" class="related-link">Configuración de perfil</a>
</div>
</div>
</div>
</div>
</div>
</article>
<!-- Pregunta 2 -->
<article class="faq-item" data-category="billing" data-question-id="2">
<div class="faq-item-inner">
<button class="question-button" aria-expanded="false">
<div class="question-content">
<h3 class="question-title">¿Qué métodos de pago aceptan?</h3>
<div class="question-meta">
<span class="last-updated">Actualizado hace 1 semana</span>
</div>
</div>
<div class="question-actions">
<button class="bookmark-btn" aria-label="Marcar como favorito">
<i class="far fa-bookmark"></i>
</button>
<button class="share-btn" aria-label="Compartir">
<i class="fas fa-share-alt"></i>
</button>
</div>
<div class="expand-indicator">
<i class="fas fa-chevron-down expand-icon"></i>
</div>
</button>
<div class="answer-section" style="max-height: 0; opacity: 0; overflow: hidden; transition: all 0.3s ease;">
<div class="answer-content">
<div class="answer-text">
<p>Aceptamos una amplia variedad de métodos de pago para tu conveniencia:</p>
<div class="payment-grid">
<div class="payment-category">
<h4>Tarjetas de Crédito/Débito</h4>
<div class="payment-items">
<div class="payment-item">
<i class="fab fa-cc-visa payment-icon"></i>
<span>Visa</span>
</div>
<div class="payment-item">
<i class="fab fa-cc-mastercard payment-icon"></i>
<span>Mastercard</span>
</div>
<div class="payment-item">
<i class="fab fa-cc-amex payment-icon"></i>
<span>American Express</span>
</div>
</div>
</div>
<div class="payment-category">
<h4>Billeteras Digitales</h4>
<div class="payment-items">
<div class="payment-item">
<i class="fab fa-paypal payment-icon"></i>
<span>PayPal</span>
</div>
<div class="payment-item">
<i class="fab fa-apple-pay payment-icon"></i>
<span>Apple Pay</span>
</div>
<div class="payment-item">
<i class="fab fa-google-pay payment-icon"></i>
<span>Google Pay</span>
</div>
</div>
</div>
</div>
</div>
<div class="answer-footer">
<div class="helpful-section">
<span class="helpful-label">¿Fue útil esta respuesta?</span>
<div class="helpful-buttons">
<button class="helpful-btn helpful-yes">
<i class="fas fa-thumbs-up"></i>
<span>Sí</span>
</button>
<button class="helpful-btn helpful-no">
<i class="fas fa-thumbs-down"></i>
<span>No</span>
</button>
</div>
</div>
<div class="related-links">
<span class="related-label">Ver también:</span>
<a href="#" class="related-link">Facturación</a>
<a href="#" class="related-link">Reembolsos</a>
</div>
</div>
</div>
</div>
</div>
</article>
<!-- Pregunta 3 -->
<article class="faq-item" data-category="account" data-question-id="3">
<div class="faq-item-inner">
<button class="question-button" aria-expanded="false">
<div class="question-content">
<h3 class="question-title">¿Cómo restablezco mi contraseña?</h3>
<div class="question-meta">
<div class="popularity-indicator">
<i class="fas fa-fire"></i>
<span>Popular</span>
</div>
<span class="last-updated">Actualizado hace 3 días</span>
</div>
</div>
<div class="question-actions">
<button class="bookmark-btn" aria-label="Marcar como favorito">
<i class="far fa-bookmark"></i>
</button>
<button class="share-btn" aria-label="Compartir">
<i class="fas fa-share-alt"></i>
</button>
</div>
<div class="expand-indicator">
<i class="fas fa-chevron-down expand-icon"></i>
</div>
</button>
<div class="answer-section" style="max-height: 0; opacity: 0; overflow: hidden; transition: all 0.3s ease;">
<div class="answer-content">
<div class="answer-text">
<p>Si olvidaste tu contraseña, puedes restablecerla fácilmente siguiendo estos pasos:</p>
<div class="reset-flow">
<div class="flow-step">
<div class="flow-icon">
<i class="fas fa-envelope"></i>
</div>
<div class="flow-content">
<h4>Solicitar restablecimiento</h4>
<p>Haz clic en "¿Olvidaste tu contraseña?" en la página de inicio de sesión</p>
</div>
</div>
<div class="flow-arrow">
<i class="fas fa-arrow-right"></i>
</div>
<div class="flow-step">
<div class="flow-icon">
<i class="fas fa-inbox"></i>
</div>
<div class="flow-content">
<h4>Revisar correo</h4>
<p>Te enviaremos un enlace de restablecimiento a tu correo registrado</p>
</div>
</div>
<div class="flow-arrow">
<i class="fas fa-arrow-right"></i>
</div>
<div class="flow-step">
<div class="flow-icon">
<i class="fas fa-key"></i>
</div>
<div class="flow-content">
<h4>Nueva contraseña</h4>
<p>Haz clic en el enlace y crea una nueva contraseña segura</p>
</div>
</div>
</div>
<div class="security-note">
<i class="fas fa-info-circle note-icon"></i>
<div class="note-content">
<strong>Importante:</strong> El enlace de restablecimiento expira en 24 horas por seguridad. Si no lo recibes, revisa tu carpeta de spam.
</div>
</div>
</div>
<div class="answer-footer">
<div class="helpful-section">
<span class="helpful-label">¿Fue útil esta respuesta?</span>
<div class="helpful-buttons">
<button class="helpful-btn helpful-yes">
<i class="fas fa-thumbs-up"></i>
<span>Sí</span>
</button>
<button class="helpful-btn helpful-no">
<i class="fas fa-thumbs-down"></i>
<span>No</span>
</button>
</div>
</div>
<div class="related-links">
<span class="related-label">Ver también:</span>
<a href="#" class="related-link">Seguridad de cuenta</a>
<a href="#" class="related-link">Autenticación de dos factores</a>
</div>
</div>
</div>
</div>
</div>
</article>
</div>
<!-- Sin resultados -->
<div class="no-results" style="display: none;">
<div class="no-results-animation">
<div class="search-animation">
<div class="search-circle"></div>
<div class="search-line"></div>
</div>
</div>
<h3>No se encontraron resultados</h3>
<p>Intenta con diferentes palabras clave o revisa la ortografía de tu búsqueda.</p>
<button class="clear-filters-btn">Limpiar filtros</button>
</div>
</main>
<!-- Acciones flotantes -->
<div class="floating-actions">
<button class="fab-main" aria-label="Menú de acciones">
<i class="fas fa-plus"></i>
</button>
<div class="fab-menu" style="display: none;">
<button class="fab-item" data-action="scroll-top">
<i class="fas fa-arrow-up"></i>
<span>Ir arriba</span>
</button>
<button class="fab-item" data-action="expand-all">
<i class="fas fa-expand-arrows-alt"></i>
<span>Expandir todo</span>
</button>
<button class="fab-item" data-action="collapse-all">
<i class="fas fa-compress-arrows-alt"></i>
<span>Contraer todo</span>
</button>
<button class="fab-item" data-action="print">
<i class="fas fa-print"></i>
<span>Imprimir</span>
</button>
</div>
</div>
</div>Estilos CSS
/* Variables CSS */
:root {
/* Colores principales */
--primary-color: #6366f1;
--primary-light: #818cf8;
--primary-dark: #4f46e5;
--accent-color: #10b981;
--error-color: #ef4444;
/* Colores de fondo */
--bg-primary: #ffffff;
--bg-secondary: #f8fafc;
--bg-tertiary: #f1f5f9;
/* Colores de texto */
--text-primary: #1e293b;
--text-secondary: #475569;
--text-tertiary: #64748b;
--text-inverse: #ffffff;
/* Colores de borde */
--border-color: #e2e8f0;
--border-hover: #cbd5e1;
/* Efectos de cristal */
--glass-bg: rgba(255, 255, 255, 0.25);
--glass-border: rgba(255, 255, 255, 0.18);
--backdrop-blur: blur(16px);
/* Sombras */
--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
--shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
/* Transiciones */
--transition-fast: 0.15s ease;
--transition-normal: 0.3s ease;
--transition-slow: 0.5s ease;
}
/* Tema oscuro */
[data-theme="dark"] {
--bg-primary: #0f172a;
--bg-secondary: #1e293b;
--bg-tertiary: #334155;
--text-primary: #f8fafc;
--text-secondary: #cbd5e1;
--text-tertiary: #94a3b8;
--border-color: #334155;
--border-hover: #475569;
--glass-bg: rgba(15, 23, 42, 0.25);
--glass-border: rgba(148, 163, 184, 0.18);
}
/* Estilos base */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
line-height: 1.6;
color: var(--text-primary);
background: var(--bg-primary);
transition: all var(--transition-normal);
}
/* Contenedor principal */
.modern-faq-container {
min-height: 100vh;
background: linear-gradient(135deg,
rgba(99, 102, 241, 0.1) 0%,
rgba(16, 185, 129, 0.1) 100%);
position: relative;
overflow-x: hidden;
}
/* Elementos de fondo */
.background-elements {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: -1;
}
.floating-shape {
position: absolute;
border-radius: 50%;
background: linear-gradient(135deg,
rgba(99, 102, 241, 0.1),
rgba(16, 185, 129, 0.1));
animation: float 6s ease-in-out infinite;
}
.shape-1 {
width: 200px;
height: 200px;
top: 10%;
left: 10%;
animation-delay: 0s;
}
.shape-2 {
width: 150px;
height: 150px;
top: 60%;
right: 10%;
animation-delay: 2s;
}
.shape-3 {
width: 100px;
height: 100px;
bottom: 20%;
left: 20%;
animation-delay: 4s;
}
.gradient-orb {
position: absolute;
border-radius: 50%;
filter: blur(40px);
animation: pulse 4s ease-in-out infinite;
}
.orb-1 {
width: 300px;
height: 300px;
background: radial-gradient(circle, rgba(99, 102, 241, 0.3), transparent);
top: 20%;
right: 20%;
animation-delay: 1s;
}
.orb-2 {
width: 250px;
height: 250px;
background: radial-gradient(circle, rgba(16, 185, 129, 0.3), transparent);
bottom: 30%;
left: 30%;
animation-delay: 3s;
}
@keyframes float {
0%, 100% {
transform: translateY(0px) rotate(0deg);
}
50% {
transform: translateY(-20px) rotate(180deg);
}
}
@keyframes pulse {
0%, 100% {
opacity: 0.3;
transform: scale(1);
}
50% {
opacity: 0.6;
transform: scale(1.1);
}
}
/* Encabezado */
.faq-header {
padding: 3rem 2rem 2rem;
text-align: center;
position: relative;
}
.header-content {
max-width: 800px;
margin: 0 auto;
}
.main-title {
font-size: 3.5rem;
font-weight: 800;
background: linear-gradient(135deg, var(--primary-color), var(--accent-color));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
margin-bottom: 1rem;
line-height: 1.2;
}
.subtitle {
font-size: 1.25rem;
color: var(--text-secondary);
font-weight: 400;
max-width: 600px;
margin: 0 auto;
}
.header-controls {
position: absolute;
top: 2rem;
right: 2rem;
}
.theme-toggle {
width: 48px;
height: 48px;
border-radius: 50%;
background: var(--glass-bg);
border: 1px solid var(--glass-border);
backdrop-filter: var(--backdrop-blur);
color: var(--text-primary);
cursor: pointer;
transition: all var(--transition-normal);
display: flex;
align-items: center;
justify-content: center;
font-size: 1.2rem;
}
.theme-toggle:hover {
background: var(--primary-color);
color: var(--text-inverse);
transform: scale(1.1);
box-shadow: var(--shadow-lg);
}
/* Sección de búsqueda */
.search-section {
padding: 0 2rem 2rem;
max-width: 800px;
margin: 0 auto;
}
.search-input-wrapper {
position: relative;
margin-bottom: 2rem;
}
.search-input {
width: 100%;
padding: 1.25rem 1.25rem 1.25rem 4rem;
font-size: 1.1rem;
border: 1px solid var(--glass-border);
border-radius: 20px;
background: var(--glass-bg);
backdrop-filter: var(--backdrop-blur);
color: var(--text-primary);
transition: all var(--transition-normal);
outline: none;
}
.search-input:focus {
border-color: var(--primary-color);
box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.1);
background: var(--bg-primary);
}
.search-input::placeholder {
color: var(--text-tertiary);
}
.search-icon {
position: absolute;
left: 1.5rem;
top: 50%;
transform: translateY(-50%);
color: var(--text-tertiary);
font-size: 1.1rem;
pointer-events: none;
}
.voice-search-btn,
.clear-search {
position: absolute;
top: 50%;
transform: translateY(-50%);
width: 40px;
height: 40px;
border: none;
border-radius: 50%;
background: none;
color: var(--text-tertiary);
cursor: pointer;
transition: all var(--transition-fast);
display: flex;
align-items: center;
justify-content: center;
}
.voice-search-btn {
right: 4rem;
}
.clear-search {
right: 1rem;
}
.voice-search-btn:hover,
.clear-search:hover {
background: var(--bg-tertiary);
color: var(--primary-color);
transform: translateY(-50%) scale(1.1);
}
.voice-search-btn.listening {
background: var(--error-color);
color: var(--text-inverse);
animation: pulse 1s infinite;
}
/* Sugerencias de búsqueda */
.search-suggestions {
position: absolute;
top: 100%;
left: 0;
right: 0;
background: var(--glass-bg);
backdrop-filter: var(--backdrop-blur);
border: 1px solid var(--glass-border);
border-radius: 16px;
margin-top: 0.5rem;
box-shadow: var(--shadow-lg);
z-index: 10;
}
.suggestion-item {
padding: 0.75rem 1.5rem;
cursor: pointer;
transition: all var(--transition-fast);
border-bottom: 1px solid var(--border-color);
}
.suggestion-item:last-child {
border-bottom: none;
}
.suggestion-item:hover {
background: var(--primary-color);
color: var(--text-inverse);
}
/* Chips de filtro */
.filter-chips {
display: flex;
gap: 1rem;
flex-wrap: wrap;
justify-content: center;
}
.filter-chip {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.75rem 1.5rem;
background: var(--glass-bg);
border: 1px solid var(--glass-border);
border-radius: 50px;
color: var(--text-secondary);
cursor: pointer;
transition: all var(--transition-normal);
backdrop-filter: var(--backdrop-blur);
font-family: inherit;
font-size: 0.9rem;
font-weight: 500;
}
.filter-chip:hover {
background: var(--bg-primary);
border-color: var(--primary-color);
color: var(--primary-color);
transform: translateY(-2px);
box-shadow: var(--shadow-md);
}
.filter-chip.active {
background: var(--primary-color);
border-color: var(--primary-color);
color: var(--text-inverse);
box-shadow: var(--shadow-lg);
}
.chip-count {
background: rgba(255, 255, 255, 0.2);
padding: 0.25rem 0.5rem;
border-radius: 12px;
font-size: 0.8rem;
font-weight: 600;
}
.filter-chip.active .chip-count {
background: rgba(255, 255, 255, 0.3);
}
/* Contenido FAQ */
.faq-content {
max-width: 900px;
margin: 0 auto;
padding: 0 2rem 4rem;
}
/* Información de resultados */
.results-info {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 2rem;
padding: 1rem 1.5rem;
background: var(--glass-bg);
border: 1px solid var(--glass-border);
border-radius: 16px;
backdrop-filter: var(--backdrop-blur);
}
.results-meta {
display: flex;
align-items: center;
gap: 0.5rem;
color: var(--text-secondary);
font-size: 0.9rem;
}
.results-count {
font-weight: 600;
color: var(--text-primary);
}
.search-time {
color: var(--text-tertiary);
font-size: 0.85rem;
}
.view-options {
display: flex;
gap: 0.5rem;
}
.view-btn {
width: 40px;
height: 40px;
border: 1px solid var(--border-color);
border-radius: 8px;
background: none;
color: var(--text-secondary);
cursor: pointer;
transition: all var(--transition-fast);
display: flex;
align-items: center;
justify-content: center;
}
.view-btn:hover {
background: var(--bg-tertiary);
border-color: var(--primary-color);
color: var(--primary-color);
}
.view-btn.active {
background: var(--primary-color);
border-color: var(--primary-color);
color: var(--text-inverse);
}
/* Lista FAQ */
.faq-list {
display: flex;
flex-direction: column;
gap: 1.5rem;
}
/* Elemento FAQ */
.faq-item {
background: var(--glass-bg);
border: 1px solid var(--glass-border);
border-radius: 20px;
backdrop-filter: var(--backdrop-blur);
transition: all var(--transition-normal);
overflow: hidden;
}
.faq-item:hover {
background: var(--bg-primary);
border-color: var(--primary-color);
transform: translateY(-2px);
box-shadow: var(--shadow-xl);
}
.faq-item-inner {
padding: 1.5rem;
}
/* Botón de pregunta */
.question-button {
width: 100%;
background: none;
border: none;
text-align: left;
cursor: pointer;
display: flex;
align-items: center;
gap: 1.5rem;
transition: all var(--transition-normal);
font-family: inherit;
}
.question-content {
flex: 1;
}
.question-title {
font-size: 1.25rem;
font-weight: 600;
color: var(--text-primary);
margin-bottom: 0.5rem;
line-height: 1.4;
transition: all var(--transition-fast);
}
.question-button:hover .question-title {
color: var(--primary-color);
}
.question-meta {
display: flex;
align-items: center;
gap: 1rem;
font-size: 0.85rem;
color: var(--text-tertiary);
}
.popularity-indicator {
display: flex;
align-items: center;
gap: 0.25rem;
}
.last-updated {
font-size: 0.8rem;
}
.expand-indicator {
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
border-radius: 50%;
background: var(--bg-tertiary);
transition: all var(--transition-normal);
}
.question-button:hover .expand-indicator {
background: var(--primary-color);
transform: scale(1.1);
}
.question-button:hover .expand-icon {
color: var(--text-inverse);
}
.expand-icon {
transition: all var(--transition-normal);
color: var(--text-secondary);
}
.question-button[aria-expanded="true"] .expand-icon {
transform: rotate(180deg);
}
/* Sección de respuesta */
.answer-section {
margin-top: 1.5rem;
animation: slideDown var(--transition-normal) ease;
}
.answer-content {
padding: 1.5rem;
background: var(--bg-secondary);
border-radius: 16px;
border: 1px solid var(--border-color);
}
.answer-text {
color: var(--text-secondary);
line-height: 1.7;
margin-bottom: 1.5rem;
}
.answer-text p {
margin-bottom: 1rem;
}
.answer-text h4 {
color: var(--text-primary);
font-weight: 600;
margin-bottom: 0.5rem;
}
/* Lista de pasos */
.step-list {
display: flex;
flex-direction: column;
gap: 1rem;
margin: 1.5rem 0;
}
.step-item {
display: flex;
gap: 1rem;
align-items: flex-start;
}
.step-number {
flex-shrink: 0;
width: 32px;
height: 32px;
background: linear-gradient(135deg, var(--primary-color), var(--primary-light));
color: var(--text-inverse);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-weight: 600;
font-size: 0.9rem;
}
.step-content h4 {
margin-bottom: 0.25rem;
}
.step-content p {
margin: 0;
font-size: 0.9rem;
}
/* Cuadrícula de pagos */
.payment-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1.5rem;
margin: 1.5rem 0;
}
.payment-category h4 {
margin-bottom: 1rem;
padding-bottom: 0.5rem;
border-bottom: 2px solid var(--border-color);
}
.payment-items {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
gap: 0.75rem;
}
.payment-item {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.75rem;
background: var(--bg-tertiary);
border-radius: 8px;
font-size: 0.9rem;
transition: all var(--transition-fast);
}
.payment-item:hover {
background: var(--primary-color);
color: var(--text-inverse);
transform: translateY(-2px);
}
.payment-icon {
font-size: 1.1rem;
}
/* Flujo de restablecimiento */
.reset-flow {
display: flex;
align-items: center;
gap: 1rem;
margin: 1.5rem 0;
overflow-x: auto;
padding: 1rem 0;
}
.flow-step {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
min-width: 150px;
flex-shrink: 0;
}
.flow-icon {
width: 48px;
height: 48px;
background: linear-gradient(135deg, var(--primary-color), var(--primary-light));
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.5rem;
margin-bottom: 0.75rem;
box-shadow: var(--shadow-md);
}
.flow-content h4 {
font-size: 0.9rem;
margin-bottom: 0.25rem;
}
.flow-content p {
font-size: 0.8rem;
margin: 0;
}
.flow-arrow {
font-size: 1.5rem;
color: var(--text-tertiary);
flex-shrink: 0;
}
/* Nota de seguridad */
.security-note {
display: flex;
gap: 0.75rem;
padding: 1rem;
background: linear-gradient(135deg, rgba(16, 185, 129, 0.1), rgba(16, 185, 129, 0.05));
border: 1px solid rgba(16, 185, 129, 0.2);
border-radius: 12px;
margin-top: 1.5rem;
}
.note-icon {
font-size: 1.25rem;
flex-shrink: 0;
}
.note-content {
font-size: 0.9rem;
line-height: 1.5;
}
.note-content strong {
color: var(--accent-color);
font-weight: 600;
}
/* Pie de respuesta */
.answer-footer {
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 1rem;
padding-top: 1.5rem;
border-top: 1px solid var(--border-color);
}
.helpful-section {
display: flex;
align-items: center;
gap: 1rem;
}
.helpful-label {
font-size: 0.9rem;
color: var(--text-secondary);
font-weight: 500;
}
.helpful-buttons {
display: flex;
gap: 0.5rem;
}
.helpful-btn {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.5rem 1rem;
background: none;
border: 1px solid var(--border-color);
border-radius: 8px;
color: var(--text-secondary);
cursor: pointer;
transition: all var(--transition-fast);
font-family: inherit;
font-size: 0.85rem;
}
.helpful-btn:hover {
background: var(--bg-tertiary);
border-color: var(--border-hover);
transform: translateY(-1px);
}
.helpful-yes:hover {
background: var(--accent-color);
border-color: var(--accent-color);
color: var(--text-inverse);
}
.helpful-no:hover {
background: var(--error-color);
border-color: var(--error-color);
color: var(--text-inverse);
}
.helpful-btn.voted {
pointer-events: none;
opacity: 0.6;
}
/* Enlaces relacionados */
.related-links {
display: flex;
align-items: center;
gap: 0.75rem;
flex-wrap: wrap;
}
.related-label {
font-size: 0.85rem;
color: var(--text-tertiary);
font-weight: 500;
}
.related-link {
color: var(--primary-color);
text-decoration: none;
font-size: 0.85rem;
padding: 0.25rem 0.5rem;
border-radius: 6px;
transition: all var(--transition-fast);
}
.related-link:hover {
background: var(--primary-color);
color: var(--text-inverse);
transform: translateY(-1px);
}
/* Sin resultados */
.no-results {
text-align: center;
padding: 4rem 2rem;
color: var(--text-secondary);
}
.no-results-animation {
margin-bottom: 2rem;
display: flex;
justify-content: center;
}
.search-animation {
position: relative;
width: 80px;
height: 80px;
}
.search-circle {
width: 50px;
height: 50px;
border: 3px solid var(--border-color);
border-radius: 50%;
position: absolute;
top: 10px;
left: 10px;
animation: searchPulse 2s ease-in-out infinite;
}
.search-line {
width: 20px;
height: 3px;
background: var(--text-tertiary);
position: absolute;
bottom: 10px;
right: 10px;
border-radius: 2px;
transform: rotate(45deg);
animation: searchPulse 2s ease-in-out infinite 0.5s;
}
@keyframes searchPulse {
0%, 100% { opacity: 0.3; transform: scale(1); }
50% { opacity: 1; transform: scale(1.1); }
}
.no-results h3 {
font-size: 1.5rem;
margin-bottom: 0.5rem;
color: var(--text-primary);
}
.no-results p {
margin-bottom: 1.5rem;
max-width: 400px;
margin-left: auto;
margin-right: auto;
}
.clear-filters-btn {
background: var(--primary-color);
color: var(--text-inverse);
border: none;
padding: 0.75rem 1.5rem;
border-radius: 12px;
cursor: pointer;
transition: all var(--transition-normal);
font-family: inherit;
font-weight: 500;
}
.clear-filters-btn:hover {
background: var(--primary-dark);
transform: translateY(-2px);
box-shadow: var(--shadow-lg);
}
/* Acciones flotantes */
.floating-actions {
position: fixed;
bottom: 2rem;
right: 2rem;
z-index: 100;
}
.fab-main {
width: 56px;
height: 56px;
background: linear-gradient(135deg, var(--primary-color), var(--primary-light));
border: none;
border-radius: 50%;
color: var(--text-inverse);
cursor: pointer;
box-shadow: var(--shadow-xl);
transition: all var(--transition-normal);
display: flex;
align-items: center;
justify-content: center;
position: relative;
}
.fab-main:hover {
transform: scale(1.1) rotate(45deg);
box-shadow: 0 8px 25px rgba(99, 102, 241, 0.4);
}
.fab-menu {
position: absolute;
bottom: 70px;
right: 0;
display: flex;
flex-direction: column;
gap: 0.75rem;
animation: fabSlideUp var(--transition-normal) ease;
}
@keyframes fabSlideUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.fab-item {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 0.75rem 1rem;
background: var(--glass-bg);
border: 1px solid var(--glass-border);
border-radius: 50px;
color: var(--text-primary);
cursor: pointer;
transition: all var(--transition-fast);
backdrop-filter: var(--backdrop-blur);
font-family: inherit;
font-size: 0.9rem;
white-space: nowrap;
box-shadow: var(--shadow-lg);
}
.fab-item:hover {
background: var(--primary-color);
color: var(--text-inverse);
transform: translateX(-4px);
}
/* Diseño responsive */
@media (max-width: 768px) {
.faq-header {
padding: 2rem 1rem 1rem;
}
.main-title {
font-size: 2.5rem;
}
.subtitle {
font-size: 1.1rem;
}
.search-section {
padding: 0 1rem 1rem;
}
.search-input {
padding: 1rem 1rem 1rem 3.5rem;
font-size: 1rem;
}
.filter-chips {
gap: 0.5rem;
}
.filter-chip {
padding: 0.5rem 1rem;
font-size: 0.85rem;
}
.faq-content {
padding: 0 1rem 2rem;
}
.results-info {
flex-direction: column;
gap: 1rem;
align-items: flex-start;
}
.faq-item-inner {
padding: 1rem;
}
.question-title {
font-size: 1.1rem;
}
.answer-content {
padding: 1rem;
}
.reset-flow {
flex-direction: column;
gap: 1.5rem;
}
.flow-arrow {
transform: rotate(90deg);
}
.payment-grid {
grid-template-columns: 1fr;
}
.answer-footer {
flex-direction: column;
align-items: flex-start;
}
.floating-actions {
bottom: 1rem;
right: 1rem;
}
.fab-main {
width: 48px;
height: 48px;
}
}
@media (max-width: 480px) {
.header-controls {
position: static;
margin-top: 1rem;
}
.search-input-wrapper {
border-radius: 16px;
}
.search-suggestions {
border-radius: 12px;
}
.filter-chip {
padding: 0.5rem 0.75rem;
font-size: 0.8rem;
}
.chip-count {
display: none;
}
.question-meta {
flex-direction: column;
align-items: flex-start;
gap: 0.5rem;
}
.step-list {
gap: 1.5rem;
}
.step-item {
flex-direction: column;
text-align: center;
gap: 0.75rem;
}
}
/* Estilos de impresión */
@media print {
.background-elements,
.theme-toggle,
.search-section,
.floating-actions,
.question-actions,
.helpful-section {
display: none !important;
}
.modern-faq-container {
background: white !important;
}
.faq-item {
background: white !important;
border: 1px solid #ccc !important;
break-inside: avoid;
margin-bottom: 1rem;
}
.answer-section {
display: block !important;
}
}
/* Modo de alto contraste */
@media (prefers-contrast: high) {
:root {
--glass-bg: rgba(255, 255, 255, 0.9);
--border-color: #000;
--text-tertiary: #333;
}
[data-theme="dark"] {
--glass-bg: rgba(0, 0, 0, 0.9);
--border-color: #fff;
--text-tertiary: #ccc;
}
}
/* Movimiento reducido */
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
.floating-shape,
.gradient-orb {
animation: none;
}
}Funcionalidad JavaScript
// Componente FAQ Moderno JavaScript
class ModernFAQ {
constructor(container) {
this.container = container;
this.searchInput = container.querySelector('.search-input');
this.searchSuggestions = container.querySelector('.search-suggestions');
this.filterChips = container.querySelectorAll('.filter-chip');
this.faqItems = container.querySelectorAll('.faq-item');
this.noResults = container.querySelector('.no-results');
this.resultsCount = container.querySelector('.results-count');
this.searchTime = container.querySelector('.search-time');
this.themeToggle = container.querySelector('.theme-toggle');
this.voiceSearchBtn = container.querySelector('.voice-search-btn');
this.clearSearchBtn = container.querySelector('.clear-search');
this.fabMain = container.querySelector('.fab-main');
this.fabMenu = container.querySelector('.fab-menu');
this.currentFilter = 'all';
this.searchTerm = '';
this.isVoiceSearchActive = false;
this.searchStartTime = 0;
this.init();
}
init() {
this.setupEventListeners();
this.loadTheme();
this.loadBookmarks();
this.updateResultsCount();
this.setupIntersectionObserver();
}
setupEventListeners() {
// Funcionalidad de búsqueda
this.searchInput.addEventListener('input', this.handleSearch.bind(this));
this.searchInput.addEventListener('focus', this.showSearchSuggestions.bind(this));
this.searchInput.addEventListener('blur', () => {
setTimeout(() => this.hideSearchSuggestions(), 200);
});
// Chips de filtro
this.filterChips.forEach(chip => {
chip.addEventListener('click', this.handleFilterChange.bind(this));
});
// Elementos FAQ
this.faqItems.forEach(item => {
const questionBtn = item.querySelector('.question-button');
questionBtn.addEventListener('click', this.toggleFAQItem.bind(this));
// Botones de marcador y compartir
const bookmarkBtn = item.querySelector('.bookmark-btn');
const shareBtn = item.querySelector('.share-btn');
if (bookmarkBtn) {
bookmarkBtn.addEventListener('click', (e) => {
e.stopPropagation();
this.toggleBookmark(item);
});
}
if (shareBtn) {
shareBtn.addEventListener('click', (e) => {
e.stopPropagation();
this.shareQuestion(item);
});
}
// Botones de utilidad
const helpfulBtns = item.querySelectorAll('.helpful-btn');
helpfulBtns.forEach(btn => {
btn.addEventListener('click', this.handleFeedback.bind(this));
});
});
// Cambio de tema
if (this.themeToggle) {
this.themeToggle.addEventListener('click', this.toggleTheme.bind(this));
}
// Búsqueda por voz
if (this.voiceSearchBtn) {
this.voiceSearchBtn.addEventListener('click', this.startVoiceSearch.bind(this));
}
// Limpiar búsqueda
if (this.clearSearchBtn) {
this.clearSearchBtn.addEventListener('click', this.clearSearch.bind(this));
}
// Menú FAB
if (this.fabMain) {
this.fabMain.addEventListener('click', this.toggleFABMenu.bind(this));
}
// Elementos del menú FAB
const fabItems = this.container.querySelectorAll('.fab-item');
fabItems.forEach(item => {
item.addEventListener('click', this.handleFABAction.bind(this));
});
// Navegación por teclado
this.container.addEventListener('keydown', this.handleKeyNavigation.bind(this));
// Clic fuera para cerrar menús
document.addEventListener('click', this.handleOutsideClick.bind(this));
// Sugerencias de búsqueda
const suggestionItems = this.container.querySelectorAll('.suggestion-item');
suggestionItems.forEach(item => {
item.addEventListener('click', this.selectSuggestion.bind(this));
});
}
handleSearch(e) {
this.searchStartTime = performance.now();
this.searchTerm = e.target.value.toLowerCase().trim();
this.filterFAQItems();
this.updateSearchSuggestions();
// Mostrar/ocultar botón de limpiar
if (this.clearSearchBtn) {
this.clearSearchBtn.style.display = this.searchTerm ? 'flex' : 'none';
}
// Rastrear búsqueda
this.trackSearch(this.searchTerm);
}
filterFAQItems() {
let visibleCount = 0;
this.faqItems.forEach(item => {
const category = item.dataset.category;
const questionText = item.querySelector('.question-title').textContent.toLowerCase();
const answerText = item.querySelector('.answer-text').textContent.toLowerCase();
const matchesFilter = this.currentFilter === 'all' || category === this.currentFilter;
const matchesSearch = !this.searchTerm ||
questionText.includes(this.searchTerm) ||
answerText.includes(this.searchTerm);
if (matchesFilter && matchesSearch) {
item.style.display = 'block';
this.highlightSearchTerm(item);
visibleCount++;
} else {
item.style.display = 'none';
this.removeHighlight(item);
}
});
this.updateResultsCount(visibleCount);
this.toggleNoResults(visibleCount === 0);
this.updateSearchTime();
}
highlightSearchTerm(item) {
if (!this.searchTerm) return;
const questionTitle = item.querySelector('.question-title');
const answerText = item.querySelector('.answer-text');
[questionTitle, answerText].forEach(element => {
if (element) {
const text = element.textContent;
const regex = new RegExp(`(${this.escapeRegex(this.searchTerm)})`, 'gi');
const highlightedText = text.replace(regex, '<mark class="search-highlight">$1</mark>');
element.innerHTML = highlightedText;
}
});
}
removeHighlight(item) {
const highlights = item.querySelectorAll('.search-highlight');
highlights.forEach(highlight => {
const parent = highlight.parentNode;
parent.replaceChild(document.createTextNode(highlight.textContent), highlight);
parent.normalize();
});
}
escapeRegex(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
updateResultsCount(count = null) {
if (count === null) {
count = Array.from(this.faqItems).filter(item =>
item.style.display !== 'none'
).length;
}
if (this.resultsCount) {
this.resultsCount.textContent = `${count} resultado${count !== 1 ? 's' : ''}`;
}
}
updateSearchTime() {
if (this.searchTime && this.searchStartTime) {
const endTime = performance.now();
const duration = ((endTime - this.searchStartTime) / 1000).toFixed(3);
this.searchTime.textContent = `(${duration}s)`;
}
}
toggleNoResults(show) {
if (this.noResults) {
this.noResults.style.display = show ? 'block' : 'none';
}
}
handleFilterChange(e) {
const chip = e.currentTarget;
const filter = chip.dataset.filter;
// Actualizar estado activo
this.filterChips.forEach(c => c.classList.remove('active'));
chip.classList.add('active');
this.currentFilter = filter;
this.filterFAQItems();
// Rastrear filtro
this.trackEvent('filter_change', { filter });
}
toggleFAQItem(e) {
const button = e.currentTarget;
const item = button.closest('.faq-item');
const answerSection = item.querySelector('.answer-section');
const isExpanded = button.getAttribute('aria-expanded') === 'true';
// Alternar estado
button.setAttribute('aria-expanded', !isExpanded);
if (!isExpanded) {
// Expandir
answerSection.style.maxHeight = answerSection.scrollHeight + 'px';
answerSection.style.opacity = '1';
answerSection.style.overflow = 'visible';
} else {
// Contraer
answerSection.style.maxHeight = '0';
answerSection.style.opacity = '0';
answerSection.style.overflow = 'hidden';
}
// Rastrear expansión
const questionId = item.dataset.questionId;
this.trackEvent('question_expand', {
question_id: questionId,
expanded: !isExpanded
});
}
toggleBookmark(item) {
const bookmarkBtn = item.querySelector('.bookmark-btn');
const icon = bookmarkBtn.querySelector('i');
const questionId = item.dataset.questionId;
const isBookmarked = icon.classList.contains('fas');
if (isBookmarked) {
icon.classList.remove('fas');
icon.classList.add('far');
this.removeBookmark(questionId);
this.showToast('Marcador eliminado');
} else {
icon.classList.remove('far');
icon.classList.add('fas');
this.saveBookmark(questionId);
this.showToast('Marcador guardado');
}
}
shareQuestion(item) {
const questionTitle = item.querySelector('.question-title').textContent;
const questionId = item.dataset.questionId;
if (navigator.share) {
navigator.share({
title: questionTitle,
text: 'Revisa esta pregunta frecuente',
url: `${window.location.href}#faq-${questionId}`
}).catch(console.error);
} else {
// Fallback: copiar al portapapeles
const url = `${window.location.href}#faq-${questionId}`;
navigator.clipboard.writeText(url).then(() => {
this.showToast('Enlace copiado al portapapeles');
}).catch(() => {
this.showToast('No se pudo copiar el enlace');
});
}
this.trackEvent('question_share', { question_id: questionId });
}
handleFeedback(e) {
const button = e.currentTarget;
const isHelpful = button.classList.contains('helpful-yes');
const item = button.closest('.faq-item');
const questionId = item.dataset.questionId;
// Deshabilitar ambos botones
const helpfulBtns = item.querySelectorAll('.helpful-btn');
helpfulBtns.forEach(btn => btn.classList.add('voted'));
// Mostrar mensaje de agradecimiento
this.showToast(isHelpful ? '¡Gracias por tu comentario!' : 'Gracias, trabajaremos para mejorar');
// Rastrear feedback
this.trackEvent('feedback', {
question_id: questionId,
helpful: isHelpful
});
}
toggleTheme() {
const currentTheme = this.container.dataset.theme;
const newTheme = currentTheme === 'light' ? 'dark' : 'light';
this.container.dataset.theme = newTheme;
localStorage.setItem('faq-theme', newTheme);
// Actualizar icono
const icon = this.themeToggle.querySelector('i');
icon.className = newTheme === 'light' ? 'fas fa-moon' : 'fas fa-sun';
this.trackEvent('theme_change', { theme: newTheme });
}
loadTheme() {
const savedTheme = localStorage.getItem('faq-theme') || 'light';
this.container.dataset.theme = savedTheme;
if (this.themeToggle) {
const icon = this.themeToggle.querySelector('i');
icon.className = savedTheme === 'light' ? 'fas fa-moon' : 'fas fa-sun';
}
}
startVoiceSearch() {
if (!('webkitSpeechRecognition' in window) && !('SpeechRecognition' in window)) {
this.showToast('Búsqueda por voz no soportada en este navegador');
return;
}
const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
const recognition = new SpeechRecognition();
recognition.lang = 'es-ES';
recognition.continuous = false;
recognition.interimResults = false;
this.voiceSearchBtn.classList.add('listening');
this.isVoiceSearchActive = true;
recognition.onresult = (event) => {
const transcript = event.results[0][0].transcript;
this.searchInput.value = transcript;
this.handleSearch({ target: { value: transcript } });
this.showToast(`Búsqueda por voz: "${transcript}"`);
};
recognition.onerror = () => {
this.showToast('Error en la búsqueda por voz');
};
recognition.onend = () => {
this.voiceSearchBtn.classList.remove('listening');
this.isVoiceSearchActive = false;
};
recognition.start();
this.trackEvent('voice_search_start');
}
clearSearch() {
this.searchInput.value = '';
this.searchTerm = '';
this.filterFAQItems();
this.hideSearchSuggestions();
if (this.clearSearchBtn) {
this.clearSearchBtn.style.display = 'none';
}
this.searchInput.focus();
this.trackEvent('search_clear');
}
toggleFABMenu() {
const isVisible = this.fabMenu.style.display === 'block';
this.fabMenu.style.display = isVisible ? 'none' : 'block';
// Rotar icono principal
const icon = this.fabMain.querySelector('i');
icon.style.transform = isVisible ? 'rotate(0deg)' : 'rotate(45deg)';
}
handleFABAction(e) {
const action = e.currentTarget.dataset.action;
switch (action) {
case 'scroll-top':
window.scrollTo({ top: 0, behavior: 'smooth' });
break;
case 'expand-all':
this.expandAllFAQs();
break;
case 'collapse-all':
this.collapseAllFAQs();
break;
case 'print':
window.print();
break;
}
this.toggleFABMenu();
this.trackEvent('fab_action', { action });
}
expandAllFAQs() {
this.faqItems.forEach(item => {
if (item.style.display !== 'none') {
const button = item.querySelector('.question-button');
const answerSection = item.querySelector('.answer-section');
button.setAttribute('aria-expanded', 'true');
answerSection.style.maxHeight = answerSection.scrollHeight + 'px';
answerSection.style.opacity = '1';
answerSection.style.overflow = 'visible';
}
});
this.showToast('Todas las preguntas expandidas');
}
collapseAllFAQs() {
this.faqItems.forEach(item => {
const button = item.querySelector('.question-button');
const answerSection = item.querySelector('.answer-section');
button.setAttribute('aria-expanded', 'false');
answerSection.style.maxHeight = '0';
answerSection.style.opacity = '0';
answerSection.style.overflow = 'hidden';
});
this.showToast('Todas las preguntas contraídas');
}
handleKeyNavigation(e) {
if (e.target.matches('.search-input')) {
this.handleSearchKeyNavigation(e);
} else if (e.target.matches('.question-button')) {
this.handleFAQKeyNavigation(e);
}
}
handleSearchKeyNavigation(e) {
const suggestions = this.container.querySelectorAll('.suggestion-item');
if (e.key === 'ArrowDown' && suggestions.length > 0) {
e.preventDefault();
suggestions[0].focus();
} else if (e.key === 'Escape') {
this.hideSearchSuggestions();
this.searchInput.blur();
}
}
handleFAQKeyNavigation(e) {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
e.target.click();
}
}
handleOutsideClick(e) {
// Cerrar sugerencias de búsqueda
if (!this.searchInput.contains(e.target) &&
!this.searchSuggestions.contains(e.target)) {
this.hideSearchSuggestions();
}
// Cerrar menú FAB
if (!this.fabMain.contains(e.target) &&
!this.fabMenu.contains(e.target)) {
this.fabMenu.style.display = 'none';
const icon = this.fabMain.querySelector('i');
icon.style.transform = 'rotate(0deg)';
}
}
showSearchSuggestions() {
if (this.searchSuggestions && this.searchTerm.length > 0) {
this.updateSearchSuggestions();
this.searchSuggestions.style.display = 'block';
}
}
hideSearchSuggestions() {
if (this.searchSuggestions) {
this.searchSuggestions.style.display = 'none';
}
}
updateSearchSuggestions() {
// Implementar lógica de sugerencias basada en el término de búsqueda
const suggestions = ['facturación', 'cuenta', 'contraseña', 'soporte'];
const filteredSuggestions = suggestions.filter(s =>
s.includes(this.searchTerm) && s !== this.searchTerm
);
this.displaySuggestions(filteredSuggestions);
}
displaySuggestions(suggestions) {
if (!this.searchSuggestions) return;
this.searchSuggestions.innerHTML = '';
suggestions.slice(0, 4).forEach(suggestion => {
const item = document.createElement('div');
item.className = 'suggestion-item';
item.textContent = suggestion;
item.addEventListener('click', () => this.selectSuggestion({ target: item }));
this.searchSuggestions.appendChild(item);
});
this.searchSuggestions.style.display = suggestions.length > 0 ? 'block' : 'none';
}
selectSuggestion(e) {
const suggestion = e.target.textContent;
this.searchInput.value = suggestion;
this.handleSearch({ target: { value: suggestion } });
this.hideSearchSuggestions();
this.searchInput.focus();
}
saveBookmark(questionId) {
const bookmarks = this.getBookmarks();
if (!bookmarks.includes(questionId)) {
bookmarks.push(questionId);
localStorage.setItem('faq-bookmarks', JSON.stringify(bookmarks));
}
}
removeBookmark(questionId) {
const bookmarks = this.getBookmarks();
const index = bookmarks.indexOf(questionId);
if (index > -1) {
bookmarks.splice(index, 1);
localStorage.setItem('faq-bookmarks', JSON.stringify(bookmarks));
}
}
getBookmarks() {
return JSON.parse(localStorage.getItem('faq-bookmarks') || '[]');
}
loadBookmarks() {
const bookmarks = this.getBookmarks();
this.faqItems.forEach(item => {
const questionId = item.dataset.questionId;
const bookmarkBtn = item.querySelector('.bookmark-btn');
const icon = bookmarkBtn?.querySelector('i');
if (icon && bookmarks.includes(questionId)) {
icon.classList.remove('far');
icon.classList.add('fas');
}
});
}
showToast(message) {
// Crear elemento toast si no existe
let toast = document.querySelector('.toast-notification');
if (!toast) {
toast = document.createElement('div');
toast.className = 'toast-notification';
document.body.appendChild(toast);
}
toast.textContent = message;
toast.style.cssText = `
position: fixed;
bottom: 2rem;
left: 50%;
transform: translateX(-50%);
background: var(--primary-color);
color: var(--text-inverse);
padding: 0.75rem 1.5rem;
border-radius: 12px;
box-shadow: var(--shadow-lg);
z-index: 1000;
opacity: 0;
transition: all 0.3s ease;
`;
// Mostrar toast
setTimeout(() => {
toast.style.opacity = '1';
toast.style.transform = 'translateX(-50%) translateY(-10px)';
}, 100);
// Ocultar toast
setTimeout(() => {
toast.style.opacity = '0';
toast.style.transform = 'translateX(-50%) translateY(0)';
}, 3000);
}
setupIntersectionObserver() {
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.style.animation = 'fadeInUp 0.6s ease forwards';
}
});
}, {
threshold: 0.1,
rootMargin: '0px 0px -50px 0px'
});
this.faqItems.forEach(item => {
observer.observe(item);
});
}
trackEvent(eventName, data = {}) {
// Implementar seguimiento de eventos (Google Analytics, etc.)
if (typeof gtag !== 'undefined') {
gtag('event', eventName, {
event_category: 'FAQ',
...data
});
}
console.log('Evento rastreado:', eventName, data);
}
trackSearch(term) {
this.debounce(() => {
this.trackEvent('search', { search_term: term });
}, 500)();
}
debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
}
// Animación CSS adicional
const additionalCSS = `
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.search-highlight {
background: linear-gradient(135deg, rgba(255, 235, 59, 0.8), rgba(255, 193, 7, 0.8));
padding: 0.1em 0.2em;
border-radius: 3px;
font-weight: 600;
}
.toast-notification {
font-family: inherit;
font-weight: 500;
backdrop-filter: blur(10px);
}
`;
// Agregar CSS adicional
const styleSheet = document.createElement('style');
styleSheet.textContent = additionalCSS;
document.head.appendChild(styleSheet);
// Inicializar cuando el DOM esté listo
document.addEventListener('DOMContentLoaded', () => {
const faqContainer = document.querySelector('.modern-faq-container');
if (faqContainer) {
new ModernFAQ(faqContainer);
}
});Instrucciones de Uso
- Instalación: Copia el HTML, CSS y JavaScript en tu proyecto
- Dependencias: Incluye Font Awesome para los iconos
- Personalización: Modifica las variables CSS para ajustar colores y estilos
- Contenido: Actualiza las preguntas y respuestas según tus necesidades
Opciones de Personalización
- Colores: Modifica las variables CSS en
:root - Animaciones: Ajusta las duraciones en
--transition-* - Efectos de cristal: Personaliza
--glass-bgy--backdrop-blur - Categorías: Añade nuevos filtros modificando los chips
- Contenido: Agrega más preguntas siguiendo la estructura HTML
Características Destacadas
- ✨ Diseño Glassmorphism: Efectos de cristal modernos
- 🔍 Búsqueda Inteligente: Filtrado en tiempo real con resaltado
- 🎨 Modo Oscuro: Cambio automático de tema
- 📱 Totalmente Responsive: Optimizado para todos los dispositivos
- ♿ Accesible: Navegación por teclado y soporte ARIA
- 🎤 Búsqueda por Voz: Reconocimiento de voz integrado
- 📊 Analíticas: Seguimiento de eventos incorporado
- ⚡ Alto Rendimiento: Optimizado para velocidad
Soporte de Navegadores
- Chrome 90+
- Firefox 88+
- Safari 14+
- Edge 90+
Rendimiento
- Carga inicial: < 50KB (comprimido)
- Tiempo de respuesta: < 100ms
- Puntuación Lighthouse: 95+
- Optimizado para Core Web Vitals
HTML
48
líneas
CSS
180
líneas
JavaScript
37
líneas
<div class="modern-faq-container">
<div class="faq-header">
<h1>FAQ Moderno</h1>
<p>Diseño glassmorphism con animaciones suaves</p>
</div>
<div class="faq-wrapper">
<div class="faq-item">
<div class="faq-question">
<h3>¿Qué hace moderno a este FAQ?</h3>
<div class="question-icon">+</div>
</div>
<div class="faq-answer">
<p>Este FAQ presenta diseño glassmorphism, micro-interacciones suaves y patrones de UI modernos con animaciones CSS avanzadas y filtros de fondo.</p>
</div>
</div>
<div class="faq-item">
<div class="faq-question">
<h3>¿Cómo funciona el efecto glassmorphism?</h3>
<div class="question-icon">+</div>
</div>
<div class="faq-answer">
<p>El efecto glassmorphism utiliza backdrop-filter: blur() combinado con fondos semi-transparentes para crear una apariencia de vidrio esmerilado.</p>
</div>
</div>
<div class="faq-item">
<div class="faq-question">
<h3>¿Es responsive este diseño?</h3>
<div class="question-icon">+</div>
</div>
<div class="faq-answer">
<p>Sí, el diseño es completamente responsive y se adapta hermosamente a todos los tamaños de pantalla con interacciones táctiles optimizadas para dispositivos móviles.</p>
</div>
</div>
<div class="faq-item">
<div class="faq-question">
<h3>¿Qué navegadores soportan esto?</h3>
<div class="question-icon">+</div>
</div>
<div class="faq-answer">
<p>Los navegadores modernos incluyendo Chrome, Firefox, Safari y Edge soportan todas las características. Se proporcionan fallbacks elegantes para navegadores más antiguos.</p>
</div>
</div>
</div>
</div>