Les compteurs animés : effet visuel percutant
Les compteurs animés (count-up) sont ces chiffres qui défilent de 0 jusqu’à la valeur ciblé. On les voit partout : « 500+ clients », « 10 000 projets livrés ». Voici comment les créer en JavaScript pur, sans bibliothèque.
Version simple : un compteur basique
function animerCompteur(élément, ciblé, duree = 2000) {
let debut = 0;
const increment = ciblé / (duree / 16); // 60 FPS
const timer = setInterval(() => {
debut += increment;
if (debut >= ciblé) {
élément.textContent = ciblé.toLocaleString('fr-FR');
clearInterval(timer);
} else {
élément.textContent = Math.floor(debut).toLocaleString('fr-FR');
}
}, 16);
}
// Utilisation
const el = document.querySelector('.compteur');
animerCompteur(el, 1500, 2000); // Compte jusqu'à 1500 en 2 secondes
Version avancée : avec easing (accélération/décélération)
Pour un effet plus naturel, le compteur accélère puis ralentit :
function compteurAnime(élément, debut, fin, duree) {
const debutTemps = performance.now();
// Fonction easing : ralentit à la fin
function easeOutQuad(t) {
return t * (2 - t);
}
function mettreAJour(tempsActuel) {
const progression = Math.min((tempsActuel - debutTemps) / duree, 1);
const valeur = Math.floor(debut + (fin - debut) * easeOutQuad(progression));
élément.textContent = valeur.toLocaleString('fr-FR');
if (progression < 1) {
requestAnimationFrame(mettreAJour);
}
}
requestAnimationFrame(mettreAJour);
}
// Utilisation
compteurAnime(document.getElementById('clients'), 0, 2500, 2500);
Le HTML et CSS pour l'affichage
<!-- HTML -->
<div class="stats">
<div class="stat">
<span class="compteur" data-ciblé="1500">0</span>
<span class="suffixe">+</span>
<p>Étudiants formés</p>
</div>
<div class="stat">
<span class="compteur" data-ciblé="50">0</span>
<p>Formations disponibles</p>
</div>
<div class="stat">
<span class="compteur" data-ciblé="98">0</span>
<span class="suffixe">%</span>
<p>Taux de satisfaction</p>
</div>
</div>
<style>
.stats { display: flex; justify-content: center; gap: 60px; padding: 40px; }
.stat { text-align: center; }
.compteur { font-size: 48px; font-weight: 700; color: #667eea; display: inline; }
.suffixe { font-size: 48px; font-weight: 700; color: #667eea; }
.stat p { margin-top: 8px; color: #666; font-size: 14px; text-transform: uppercase; }
</style>
Déclencher au scroll (Intersection Observer)
Le compteur ne doit se lancer que quand l'utilisateur le voit :
// Initialiser tous les compteurs au scroll
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const el = entry.target;
const ciblé = parseInt(el.dataset.ciblé);
compteurAnime(el, 0, ciblé, 2000);
observer.unobserve(el); // Ne lancer qu'une seule fois
}
});
}, { threshold: 0.5 });
// Observer chaque compteur
document.querySelectorAll('.compteur').forEach(el => {
observer.observé(el);
});
💡 Pourquoi Intersection Observer ?
Sans cela, le compteur s'anime dès le chargement de la page, même si l'utilisateur ne le voit pas. Avec l'Observer, l'animation se déclenche uniquement quand la section est visible à l'écran.
Compteur avec formatage avancé
function compteurFormate(élément, ciblé, options = {}) {
const {
duree = 2000,
prefixe = '',
suffixe = '',
decimales = 0,
separateur = ' '
} = options;
const debutTemps = performance.now();
function formater(nombre) {
const fixe = nombre.toFixed(decimales);
const [entier, decimal] = fixe.split('.');
const formate = entier.replace(/\B(?=(\d{3})+(?!\d))/g, separateur);
return prefixe + formate + (decimal ? ',' + decimal : '') + suffixe;
}
function animer(tempsActuel) {
const progression = Math.min((tempsActuel - debutTemps) / duree, 1);
const eased = 1 - Math.pow(1 - progression, 3); // easeOutCubic
const valeur = ciblé * eased;
élément.textContent = formater(valeur);
if (progression < 1) requestAnimationFrame(animer);
}
requestAnimationFrame(animer);
}
// Exemples d'utilisation
compteurFormate(el1, 2500000, { prefixe: '', suffixe: ' FCFA', separateur: ' ' });
// Résultat : "2 500 000 FCFA"
compteurFormate(el2, 99.7, { suffixe: '%', decimales: 1 });
// Résultat : "99,7%"
Code complet prêt à l'emploi
// Copier-coller ce script dans votre site
document.addEventListener('DOMContentLoaded', () => {
const compteurs = document.querySelectorAll('[data-compteur]');
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const el = entry.target;
const ciblé = parseFloat(el.dataset.compteur);
const duree = parseInt(el.dataset.duree) || 2000;
const prefixe = el.dataset.prefixe || '';
const suffixe = el.dataset.suffixe || '';
compteurAnime(el, 0, ciblé, duree);
el.dataset.prefixeVal = prefixe;
el.dataset.suffixeVal = suffixe;
observer.unobserve(el);
}
});
}, { threshold: 0.3 });
compteurs.forEach(el => observer.observé(el));
});
// HTML : <span data-compteur="1500" data-suffixe="+">0</span>
Exercice pratique
🎯 Défi : Section statistiques pour votre site
- Créez une section avec 4 compteurs : clients, projets, heures de formation, satisfaction
- Ajoutez l'effet easing pour une animation fluide
- Déclenchez l'animation au scroll avec Intersection Observer
- Formatez les grands nombres avec des espaces (ex: 10 000)
- Bonus : ajoutez une icône au-dessus de chaque compteur