Sur une boutique, le clic « ajouter au panier » est le moment qui compte. Une micro-interaction bien faite — l'article qui s'envole vers le panier, un petit burst, le compteur qui s'incrémente — confirme l'action, la rend satisfaisante et lève le doute (« est-ce que ça a marché ? »). C'est un levier de conversion simple. Cet article décrit l'effet Magnetic Add to Cart, l'effet gratuit du sprint Black Friday de novembre 2026 sur Effect.Labs, en JavaScript vanilla, sans aucune dépendance, accessible et 60fps.
1. Le bouton magnétique
Le bouton « attire » légèrement le curseur : sur pointermove, on calcule l'écart entre le curseur et le centre du bouton, et on applique une translation proportionnelle. Sur pointerleave, on réinitialise.
btn.addEventListener('pointermove', function (e) {
var r = btn.getBoundingClientRect();
var mx = e.clientX - (r.left + r.width / 2);
var my = e.clientY - (r.top + r.height / 2);
btn.style.transform = 'translate(' + (mx * 0.22) + 'px,' + (my * 0.35) + 'px)';
});
btn.addEventListener('pointerleave', function () { btn.style.transform = ''; });
2. Le burst de particules
Au clic, on génère une dizaine de petites particules (de simples <span>) à la position du bouton, projetées dans des directions aléatoires via des variables CSS et une keyframe. Léger, et auto-nettoyé après l'animation.
for (var i = 0; i < 14; i++) {
var p = document.createElement('span');
p.className = 'atc-particle';
p.style.left = x0 + 'px'; p.style.top = y0 + 'px';
var a = Math.random() * 6.2832, d = 24 + Math.random() * 46;
p.style.setProperty('--dx', Math.cos(a) * d + 'px');
p.style.setProperty('--dy', Math.sin(a) * d + 'px');
scene.appendChild(p);
setTimeout(function () { p.remove(); }, 650); // cleanup
}
.atc-particle { animation: atc-burst .6s ease-out forwards; }
@keyframes atc-burst {
to { transform: translate(-50%,-50%) translate(var(--dx), var(--dy)) scale(.2); opacity: 0; }
}
3. Le vol vers le panier (courbe de Bézier)
Le cœur de l'effet : un clone de l'article suit une courbe de Bézier quadratique du bouton jusqu'à l'icône panier. Le point de contrôle placé au-dessus des deux extrémités donne cette belle trajectoire en arc.
// P(t) = (1-t)²·P0 + 2(1-t)t·C + t²·P1
var cx = (x0 + x1) / 2, cy = Math.min(y0, y1) - 70; // point de contrôle au-dessus
(function anim(t) {
var k = Math.min((t - t0) / 620, 1);
var e = k < .5 ? 2*k*k : 1 - Math.pow(-2*k+2, 2)/2; // easing
var m = 1 - e;
var x = m*m*x0 + 2*m*e*cx + e*e*x1;
var y = m*m*y0 + 2*m*e*cy + e*e*y1;
chip.style.transform = 'translate(-50%,-50%) translate(' + (x-x0) + 'px,' + (y-y0) + 'px) scale(' + (1 - .55*e) + ')';
if (k < 1) requestAnimationFrame(anim);
else { chip.remove(); bump(); } // à l'arrivée : incrémente le panier
})(t0);
4. Le compteur qui réagit
À l'arrivée du clone, on incrémente le badge et on rejoue une petite animation de « pop » (et un tressaut du panier). L'astuce pour rejouer une animation CSS : retirer la classe, forcer un reflow (void el.offsetWidth), la remettre.
function bump() {
n++; countEl.textContent = n;
countEl.classList.remove('atc-pop'); void countEl.offsetWidth; countEl.classList.add('atc-pop');
}
Le code complet (bouton magnétique, burst, vol et compteur réunis) est disponible directement sur la page Boutons du catalogue — cet effet est gratuit.
Performance et accessibilité
Tout repose sur des transform/opacity (composés par le GPU) et un seul requestAnimationFrame par clic : c'est fluide même sur mobile. Les garde-fous :
- Un vrai
<button>: utilisable au clavier et annoncé par les lecteurs d'écran. prefers-reduced-motion: on saute le magnétisme, les particules et le vol — on garde uniquement l'incrément du compteur (le feedback essentiel).- Cleanup : particules et clone sont retirés du DOM après l'animation (pas de fuite).
Ce que ChatGPT et v0 ne font pas
Demandez une animation « add to cart » à un générateur : vous obtenez souvent une transition droite (translate linéaire) sans âme. Ce qui est régulièrement oublié :
- La courbe de Bézier : l'arc (point de contrôle au-dessus) est ce qui rend le vol naturel ; l'IA propose une ligne droite.
- prefers-reduced-motion : presque jamais géré → animation imposée à ceux qui l'ont désactivée.
- Le cleanup DOM : les particules/clones restent souvent dans le DOM (fuite mémoire sur usage répété).
- Le bouton magnétique sur
pointermoveavec reset propre, rarement inclus.
Questions fréquentes
Peut-on l'utiliser avec React, Vue ou Svelte ?
Oui : JavaScript vanilla, aucune dépendance npm. Dans React, encapsuler la logique dans un useEffect avec cleanup (retirer les particules/clones au démontage) ; dans Svelte, onMount/onDestroy.
Comment l'adapter à « ajouter aux favoris » ?
Même mécanique : remplacez l'icône panier par un cœur, l'article volant par un ❤️, et incrémentez un compteur de favoris. Le code est agnostique du contexte.
Le code complet, prêt à l'emploi
Cet effet est gratuit ce mois-ci. Copiez-collez le code et adaptez-le à votre panier. Accès à 800+ autres effets premium avec l'abonnement.
Rejoindre les fondateurs — 9,90 € / mois