<div class="container">
<h1>Count Up Animation Demo</h1>
<div class="stats-grid">
<div class="stat-card">
<div class="stat-number" data-target="1250">0</div>
<div class="stat-label">Projects</div>
</div>
<div class="stat-card">
<div class="stat-number" data-target="5840">0</div>
<div class="stat-label">Customers</div>
</div>
<div class="stat-card">
<div class="stat-number" data-target="99.9" data-decimal="1">0</div>
<div class="stat-label">Uptime %</div>
</div>
</div>
<button class="btn" onclick="resetCounters()">Reset Animation</button>
</div>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #0a0a0a 0%, #1a1a1a 100%);
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
padding: 20px;
}
.container {
text-align: center;
max-width: 1200px;
width: 100%;
}
h1 {
background: linear-gradient(90deg, #00FFFF 0%, #00CED1 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
font-size: 2.5rem;
margin-bottom: 50px;
font-weight: 600;
}
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 30px;
margin-bottom: 40px;
}
.stat-card {
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(0, 255, 255, 0.2);
border-radius: 15px;
padding: 40px 20px;
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.stat-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 30px rgba(0, 255, 255, 0.2);
}
.stat-number {
font-size: 3.5rem;
font-weight: 700;
background: linear-gradient(135deg, #00FFFF 0%, #00CED1 50%, #20B2AA 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
margin-bottom: 10px;
line-height: 1.2;
}
.stat-label {
color: #b0b0b0;
font-size: 1.1rem;
font-weight: 400;
text-transform: uppercase;
letter-spacing: 2px;
}
.btn {
background: linear-gradient(90deg, #00FFFF 0%, #00CED1 100%);
color: #0a0a0a;
border: none;
padding: 15px 40px;
font-size: 1rem;
font-weight: 600;
border-radius: 30px;
cursor: pointer;
transition: transform 0.2s ease, box-shadow 0.2s ease;
text-transform: uppercase;
letter-spacing: 1px;
}
.btn:hover {
transform: scale(1.05);
box-shadow: 0 5px 20px rgba(0, 255, 255, 0.4);
}
.btn:active {
transform: scale(0.98);
}
@media (max-width: 768px) {
h1 {
font-size: 2rem;
}
.stat-number {
font-size: 2.5rem;
}
.stat-label {
font-size: 0.9rem;
}
}
function animateCounter(element) {
const target = parseFloat(element.getAttribute('data-target'));
const decimals = parseInt(element.getAttribute('data-decimal')) || 0;
const duration = 2000; // 2 seconds
const increment = target / (duration / 16); // 60fps
let current = 0;
const timer = setInterval(() => {
current += increment;
if (current >= target) {
current = target;
clearInterval(timer);
}
element.textContent = current.toFixed(decimals);
}, 16);
}
function startCounters() {
const counters = document.querySelectorAll('.stat-number');
counters.forEach(counter => {
counter.textContent = '0';
animateCounter(counter);
});
}
function resetCounters() {
startCounters();
}
// Observer for viewport visibility
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting && entry.target.textContent === '0') {
animateCounter(entry.target);
}
});
}, { threshold: 0.5 });
// Start animation on page load
window.addEventListener('DOMContentLoaded', () => {
const counters = document.querySelectorAll('.stat-number');
counters.forEach(counter => observer.observe(counter));
startCounters();
});
No comments yet. Be the first!