Gravity Drag
Trois balles colorées flottent dans un cadre et se laissent attraper à la souris ou au doigt : relâchez et la gravité les ramène au sol avec rebond et friction. Lancez-les d'un geste sec pour observer leur trajectoire, ou posez-les délicatement pour les empiler.
Mis à jour le
Cet effet fait partie d'Effect.Labs — 840 effets vanilla, une partie gratuite, une partie premium. Hover comprend 48 effets, dont 5 gratuits. Découvrir la catégorie →
3 exemples d'usage



Comment ça marche
Chaque balle est un div.gd380-ball positionné en absolu dans la zone .gd380-zone (300 px de haut). Ses propriétés d'état (x, y, vx, vy, isDragging) sont gardées dans un tableau JavaScript. La boucle requestAnimationFrame met à jour chaque balle à chaque image avec un pas normalisé à 60 images/s : f = dt / 16.67.
Quand une balle n'est pas saisie : la gravité ajoute 0,5 × f à vy ; si y + 50 dépasse la hauteur de la zone, la balle rebondit (vy × −0,65) et perd un peu de vitesse horizontale (vx × 0,85). Si elle sort par un côté, vx est inversé. Quand elle est saisie (mousedown ou touchstart), sa position suit le curseur ou le doigt dans le repère de la zone, avec l'offset du point de prise mémorisé ; au relâcher (mouseup/touchend), la vélocité est déduite de la différence de position sur les 20 dernières ms pour permettre les lancers.
Accessibilité
- Toucher : les événements
touchstart,touchmoveettouchendpermettent de saisir et lancer les balles au doigt sur mobile et tablette.preventDefault()bloque le défilement de la page pendant la saisie. - Clavier : l'effet ne propose pas de navigation au clavier. Les balles ne sont pas des boutons et ne reçoivent pas le focus. Si un usage accessible est requis, ajoutez des
<button>invisibles qui appliquent une impulsion prédéfinie à chaque balle via Entrée. - Mouvement réduit : sous
prefers-reduced-motion: reduce, la boucle ne démarre pas ; les balles restent à leur position initiale, visibles et lisibles, sans tomber ni rebondir. - Rôle décoratif : les balles portent les mots DRAG, ME, UP en anglais — un appel à l'action intégré au visuel. Si votre contexte exige un texte accessible différent, ajoutez un
aria-labelsur.gd380-zone.
Compatibilité navigateur
DOM pur et CSS, aucune dépendance. IntersectionObserver disponible depuis Chrome 51, Firefox 55, Safari 12.1. Physique par requestAnimationFrame normalisée sur le temps écoulé : même comportement sur écran 60 Hz et 120 Hz. Non vérifié sur Safari réel ; attendu complet.
Sans JavaScript, les trois balles s'affichent à leur position initiale, fixes. Sans IntersectionObserver, la boucle tourne aussi hors écran.
Le code
Structure HTML à coller dans votre page (le CSS + JS sont inclus avec votre achat) :
<div class="fx-0380-root">
<div class="gd380-zone">
<div class="gd380-ball ball-1" data-ball="0" style="left:50px;top:60px">DRAG</div>
<div class="gd380-ball ball-2" data-ball="1" style="left:150px;top:90px">ME</div>
<div class="gd380-ball ball-3" data-ball="2" style="left:250px;top:50px">UP</div>
</div>
<span class="gd380-label" aria-hidden="true">Attrapez et lancez les balles</span>
</div>
Paiement unique, sans abonnement — le code est à toi pour toujours
Personnaliser
Options passées à l'API ou attributs data-* :
| Option / propriété | Défaut | Effet |
|---|---|---|
Gravité (JS — vy += 0.5 * f) |
0,5 px/image² (normalisé 60 fps) | 0,2 donne une chute lunaire ; 1,5 une chute rapide. Sur un écran 120 Hz, la normalisation maintient le même ressenti qu'à 60 Hz. |
Rebond (JS — vy *= -0.65) |
65 % de la vitesse conservée | 0,8 donne des rebonds très élastiques ; 0,3 un arrêt rapide. 1,0 est physiquement impossible et crée un cycle infini. |
Friction au sol (JS — vx *= 0.85) |
85 % de la vitesse horizontale conservée | 0,98 donne un long glissement ; 0,5 arrête la balle presque instantanément. |
Taille des balles (CSS — .gd380-ball { width, height }) |
50 px | Ajustez aussi les collisions avec le sol (y + 50 > zoneH) au même pixel que la hauteur réelle de la balle. |
Couleurs (CSS — .gd380-ball.ball-1, .ball-2, .ball-3) |
gradient indigo, violet, rose | Remplacez les background par vos couleurs brand. La propriété box-shadow suit si vous la conservez sur fond sombre. |
FAQ
div.gd380-ball.ball-4 dans .gd380-zone avec un style left/top initial, et ajoutez la couleur dans le CSS. Le script parcourt automatiquement tous les .gd380-ball avec querySelectorAll. Au-delà de 6 balles, les collisions entre elles ne sont pas gérées : elles se traversent.