<div class="spinner-showcase">
<div class="spinner-grid">
<!-- Spinner Clásico -->
<div class="spinner-item">
<div class="spinner classic-spinner"></div>
<span class="spinner-label">Clásico</span>
</div>
<!-- Spinner Pulso -->
<div class="spinner-item">
<div class="spinner pulse-spinner"></div>
<span class="spinner-label">Pulso</span>
</div>
<!-- Spinner Puntos -->
<div class="spinner-item">
<div class="spinner dots-spinner">
<div class="dot"></div>
<div class="dot"></div>
<div class="dot"></div>
</div>
<span class="spinner-label">Puntos</span>
</div>
<!-- Spinner Anillo -->
<div class="spinner-item">
<div class="spinner ring-spinner"></div>
<span class="spinner-label">Anillo</span>
</div>
<!-- Spinner Gradiente -->
<div class="spinner-item">
<div class="spinner gradient-spinner"></div>
<span class="spinner-label">Gradiente</span>
</div>
<!-- Spinner Rebote -->
<div class="spinner-item">
<div class="spinner bounce-spinner">
<div class="bounce-ball"></div>
<div class="bounce-ball"></div>
<div class="bounce-ball"></div>
</div>
<span class="spinner-label">Rebote</span>
</div>
</div>
</div>
.spinner-showcase {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 2rem;
}
.spinner-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 2rem;
max-width: 800px;
width: 100%;
}
.spinner-item {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 16px;
padding: 2rem;
display: flex;
flex-direction: column;
align-items: center;
gap: 1rem;
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.spinner-item:hover {
transform: translateY(-5px);
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
}
.spinner {
width: 40px;
height: 40px;
}
.spinner-label {
color: white;
font-size: 0.9rem;
font-weight: 500;
text-align: center;
}
/* Spinner Clásico */
.classic-spinner {
border: 4px solid rgba(255, 255, 255, 0.3);
border-top: 4px solid #fff;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* Spinner Pulso */
.pulse-spinner {
background: #fff;
border-radius: 50%;
animation: pulse 1.5s ease-in-out infinite;
}
@keyframes pulse {
0%, 100% {
transform: scale(0.8);
opacity: 0.5;
}
50% {
transform: scale(1.2);
opacity: 1;
}
}
/* Spinner Puntos */
.dots-spinner {
display: flex;
gap: 8px;
align-items: center;
justify-content: center;
}
.dot {
width: 8px;
height: 8px;
background: #fff;
border-radius: 50%;
animation: dotBounce 1.4s ease-in-out infinite both;
}
.dot:nth-child(1) { animation-delay: -0.32s; }
.dot:nth-child(2) { animation-delay: -0.16s; }
.dot:nth-child(3) { animation-delay: 0s; }
@keyframes dotBounce {
0%, 80%, 100% {
transform: scale(0.6);
opacity: 0.5;
}
40% {
transform: scale(1);
opacity: 1;
}
}
/* Spinner Anillo */
.ring-spinner {
border: 4px solid rgba(255, 255, 255, 0.3);
border-radius: 50%;
border-top: 4px solid transparent;
border-right: 4px solid transparent;
animation: ring 1s linear infinite;
}
.ring-spinner::before {
content: '';
position: absolute;
top: 2px;
left: 2px;
right: 2px;
bottom: 2px;
border: 2px solid transparent;
border-top: 2px solid #fff;
border-radius: 50%;
animation: ring 1.5s linear infinite reverse;
}
@keyframes ring {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* Spinner Gradiente */
.gradient-spinner {
background: conic-gradient(from 0deg, transparent, #fff, transparent);
border-radius: 50%;
animation: spin 1s linear infinite;
position: relative;
}
.gradient-spinner::before {
content: '';
position: absolute;
top: 4px;
left: 4px;
right: 4px;
bottom: 4px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 50%;
}
/* Spinner Rebote */
.bounce-spinner {
display: flex;
gap: 4px;
align-items: center;
justify-content: center;
}
.bounce-ball {
width: 10px;
height: 10px;
background: #fff;
border-radius: 50%;
animation: bounce 1.4s ease-in-out infinite both;
}
.bounce-ball:nth-child(1) { animation-delay: -0.32s; }
.bounce-ball:nth-child(2) { animation-delay: -0.16s; }
.bounce-ball:nth-child(3) { animation-delay: 0s; }
@keyframes bounce {
0%, 80%, 100% {
transform: translateY(0) scale(0.8);
opacity: 0.7;
}
40% {
transform: translateY(-20px) scale(1);
opacity: 1;
}
}
/* Diseño Responsivo */
@media (max-width: 768px) {
.spinner-grid {
grid-template-columns: repeat(2, 1fr);
gap: 1rem;
}
.spinner-item {
padding: 1.5rem;
}
}
@media (max-width: 480px) {
.spinner-grid {
grid-template-columns: 1fr;
}
}
// Opcional: Control dinámico de spinners
class ControladorSpinner {
constructor() {
this.spinnersActivos = new Set();
this.init();
}
init() {
// Agregar manejadores de clic para demostración
document.querySelectorAll('.spinner-item').forEach((item, index) => {
item.addEventListener('click', () => {
this.alternarSpinner(item, index);
});
});
}
alternarSpinner(item, index) {
const spinner = item.querySelector('.spinner');
const label = item.querySelector('.spinner-label');
if (this.spinnersActivos.has(index)) {
// Detener spinner
spinner.style.animationPlayState = 'paused';
label.textContent = label.textContent.replace(' (Pausado)', '') + ' (Pausado)';
this.spinnersActivos.delete(index);
} else {
// Iniciar spinner
spinner.style.animationPlayState = 'running';
label.textContent = label.textContent.replace(' (Pausado)', '');
this.spinnersActivos.add(index);
}
}
// Métodos de utilidad
pausarTodos() {
document.querySelectorAll('.spinner').forEach(spinner => {
spinner.style.animationPlayState = 'paused';
});
}
reanudarTodos() {
document.querySelectorAll('.spinner').forEach(spinner => {
spinner.style.animationPlayState = 'running';
});
}
}
// Inicializar controlador de spinner
document.addEventListener('DOMContentLoaded', () => {
new ControladorSpinner();
});