Particle Explosion
30 particules explosent en cercle depuis le centre d'un bouton au clic — Web Animations API, éasing cubic-bezier, 7 couleurs vives, zéro canvas.
Vous aurez accès à la démo interactive avec un compte gratuit.
Cet effet fait partie d'Effect.Labs — 811 effets vanilla, une partie gratuite, une partie premium. Atmosphère comprend 57 effets, dont 10 gratuits. Découvrir la catégorie →
3 exemples d'usage



Comment ça marche
Au clic, le code calcule la position centre du bouton dans le repère du conteneur via getBoundingClientRect(), puis crée 30 <div> positionnés à cet origine. Chaque particule reçoit un angle de départ uniformément distribué sur 360° ((Math.PI × 2 / 30) × i) — la symétrie est mathématique, pas aléatoire : les particules forment une couronne parfaite.
Le déplacement est animé via la Web Animations API (element.animate()) sans canvas ni RAF manuel. Vecteur de translation : (cos(angle) × velocity, sin(angle) × velocity) avec velocity = 80 + Math.random() × 80 px (plage 80–160 px). L'opacité passe de 1 à 0 et la transformation scale de 1 à 0 simultanément — les particules s'éteignent et rapetissent en s'éloignant.
L'éasing cubic-bezier(0, 0.5, 0.5, 1) produit un départ vif suivi d'une décélération progressive : fort gradient initial qui simule l'énergie cinétique d'une explosion, puis ralentissement vers la fin. La durée varie de 600 à 1 000 ms par particule (aléatoire par Math.random()), ce qui crée un effet de traîne naturel entre les particules les plus rapides et les plus lentes.
Chaque particule est retirée du DOM via le callback onfinish dès la fin de son animation — zéro accumulation mémoire. Les 7 couleurs (#6366f1, #8b5cf6, #d946ef, #f43f5e, #f59e0b, #22c55e, #06b6d4) sont tirées aléatoirement à l'initialisation de chaque particule. L'effet est déclenchable en rafale : chaque clic crée 30 nouveaux éléments indépendamment des précédents.
Accessibilité
- Pas de prefers-reduced-motion : l'effet ne vérifie pas la préférence système — l'explosion se déclenche toujours au clic. À implémenter manuellement (skip la boucle
forou réduire à 5 particules lentes) si l'audience cible inclut des utilisateurs sensibles aux mouvements. - Le déclencheur est un
<button>natif : focusable au clavier (Tab), activable avec Espace ou Entrée, exposé comme bouton aux lecteurs d'écran sans ARIA supplémentaire. - Le conteneur des particules n'a ni
aria-hiddennirole: les<div>transitoires peuvent générer du bruit dans l'arbre d'accessibilité sur les lecteurs d'écran les plus verbeux (NVDA, JAWS en mode ultra-bavard). Ajouteraria-hidden="true"au conteneur si les particules ne doivent pas être annoncées. - Contraste texte du bouton livré : blanc sur dégradé
#f43f5e → #f59e0b(rouge-ambré), ratio ~3,2:1 — insuffisant pour WCAG AA (4,5:1) en texte normal non-large. À corriger pour un usage production : fond plus sombre ou taille ≥ 18 pt. - L'effet est entièrement DOM (pas de canvas, pas de WebGL) : aucune surface graphique opaque ne masque le contenu textuel sous-jacent.
Compatibilité navigateur
Utilise la Web Animations API (element.animate()) et getBoundingClientRect() — pas de canvas, pas de WebGL, pas de RAF manuel.
Sans support de la Web Animations API (IE 11, Safari < 13.1), les particules sont créées mais restent immobiles — pas d'erreur JS fatale. Le callback <code>onfinish</code> ne se déclenche pas : les divs s'accumulent dans le DOM. Ajouter un <code>setTimeout(el.remove, 1200)</code> sur chaque particule pour nettoyer si IE est requis.
Le code
Structure HTML à coller dans votre page (CSS + JS disponibles avec un compte premium) :
<div class="demo-preview">
<div class="explosion-container" id="explosionContainer">
<button class="explosion-btn" id="explosionBtn">Boom!</button>
</div>
</div>
HTML + CSS + JS complet, prêt à coller — avec des centaines d'effets premium.
Personnaliser
Options passées à l'API ou attributs data-* :
| Option / propriété | Défaut | Effet |
|---|---|---|
| colors (tableau ligne 2 du JS) | ['#6366f1','#8b5cf6','#d946ef','#f43f5e','#f59e0b','#22c55e','#06b6d4'] | Remplacez les 7 valeurs hex par votre palette. Chaque particule pioche une couleur aléatoirement dans ce tableau à sa création. |
| Nombre de particules (boucle for i < 30) | 30 | Augmenter à 50–80 pour un burst plus dense et spectaculaire ; descendre à 10–15 pour un effet discret. La charge DOM est proportionnelle au nombre. |
| velocity (const velocity = 80 + Math.random() * 80) | 80–160 px | Premier terme = rayon minimum (80 px), deuxième = amplitude aléatoire (+80 px max). Élargir la plage (ex. 60 + random * 160) pour un effet plus explosif et irrégulier. |
| duration (600 + Math.random() * 400) | 600–1 000 ms | Durée de vie de chaque particule. Réduire à 300–500 ms pour une explosion vive et nerveuse ; augmenter à 900–1 400 ms pour un effet plus flottant. |
| easing (cubic-bezier(0, 0.5, 0.5, 1)) | cubic-bezier(0, 0.5, 0.5, 1) | Courbe de décélération de chaque particule. ease-out donne un résultat proche ; linear retire la décelération pour un effet plus mécanique et uniforme. |
| .explosion-particle (CSS à ajouter) | Non défini dans le CSS fourni | Définir la taille et la forme des particules. Cercle : border-radius:50%. Carré : border-radius:0. Losange : ajouter transform:rotate(45deg) en keyframe de départ. Taille recommandée : 6–12 px. |
FAQ
.explosion-particle (ni taille, ni position: absolute). Ajoutez au minimum : .explosion-particle { position: absolute; width: 8px; height: 8px; border-radius: 50%; pointer-events: none; } et vérifiez que le conteneur parent a bien position: relative ou absolute.onfinish les retire après l'animation. Il n'y a pas de verrou : plusieurs explosions peuvent se superposer en rafale. Attention si l'utilisateur clique très vite (100 clics rapides = 3 000 éléments coexistant brièvement) : ajouter un debounce de 300 ms si nécessaire.rect / containerRect par les coordonnées voulues dans le repère du conteneur : ex. e.clientX - containerRect.left pour suivre le curseur, ou des valeurs fixes pour centrer l'explosion. La logique de création des particules est indépendante de la source — seuls startX et startY changent.