Curseurs✨ Premium

Cursor Trail Effect

Cinq points fixes de 8 px, d'opacité 0,7 à 0,3, qui se poursuivent en chaîne : chacun rejoint le précédent à 30 %, 25 %, 20 %, 15 % puis 10 % de l'écart par frame. Sur un saut de 456 px la traînée s'étire jusqu'à 406 px et le dernier point met 79 frames à se recoller. Le curseur natif est masqué dans la zone.

JSTrail

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. Curseurs comprend 26 effets, dont 1 gratuits. Découvrir la catégorie →

3 exemples d'usage

Landing d'un tournoi e-sport — traînée sur le hero — Cursor Trail Effect exemple 1

① Landing d'un tournoi e-sport — traînée sur le hero

QuandPage d'événement jeu vidéo : saison, dates, un appel à l'inscription sur fond sombre.
PourquoiLe vocabulaire visuel du jeu accepte un curseur spectaculaire ; la traînée à cinq points évoque un projectile sans coûter une particule. La zone est limitée au hero pour ne pas gêner les formulaires plus bas.
RéglagesCouleur d'accent du tournoi, point de tête à opacity: 1 pour un repère net, vitesses inchangées.
Sortie d'album — panneau de lecture — Cursor Trail Effect exemple 2

② Sortie d'album — panneau de lecture

QuandBloc promotionnel : pochette, titre, artiste, une forme d'onde. Le curseur traîne sur la pochette.
PourquoiLa traînée suit le rythme de la main comme la forme d'onde suit le son ; en rose sur fond nuit, elle rappelle la pochette sans se confondre avec les commandes.
RéglagesCouleur #f472b6, points de 10 px (offset − 5 dans le JS), speed = 0.25 − i × 0.04 pour une traînée plus longue.
Studio de motion design — bande-annonce — Cursor Trail Effect exemple 3

③ Studio de motion design — bande-annonce

QuandSection « reel » d'un studio : un mot géant, l'année, un lien vers la vidéo.
PourquoiUn studio d'animation démontre son métier dès le curseur : la traînée blanche sur noir est un trait de lumière, lisible même sur le titre.
RéglagesCouleur #f5f5f4, points de 6 px (offset − 3), opacités 1, 0,7, 0,5, 0,35, 0,2 pour une extinction plus franche.

Comment ça marche

Le HTML fournit cinq div vides #trailV2-1 à #trailV2-5, tous .cursor-trail-v2position: fixed, 8 × 8 px, #6366f1, border-radius: 50%, pointer-events: none, z-index: 9999, display: none — groupés dans .cursor-trail-v2-set pour que :nth-child(1) à (5) leur donne une opacité décroissante : 0,7, 0,6, 0,5, 0,4, 0,3 (mesurées). Aucune transition CSS, à dessein : la position est réécrite à chaque frame par le JS.

La zone #zone-trail-v2 écoute mouseenter (classe cursor-active — dont la règle cursor: none !important est bien livrée, mesuré cursor: none — et display: block sur les cinq), mouseleave (l'inverse) et mousemove, qui ne fait que mémoriser trailV2X/Y. Tout le mouvement est dans une boucle requestAnimationFrame : pour le point i, la cible est le pointeur si i === 0, sinon la position du point i − 1 ; speed = 0.3 − i × 0.05 ; pos.x += (target.x − pos.x) × speed ; puis left = pos.x − 4.

C'est une chaîne d'approches exponentielles : le premier point comble 30 % de son retard par frame, le dernier 10 %, et chacun ne vise que son prédécesseur. Mesuré à 120 Hz après un saut de 456 px : écart au pointeur à la frame 5 = 54, 177, 315, 407 et 445 px pour les points 1 à 5 ; étirement maximal de la traînée 406 px à la frame 7 ; retour à moins de 1 px aux frames 17, 26, 37, 52 et 79 (≈ 0,65 s pour la queue). La longueur de la traînée dépend donc de la vitesse de la main, pas d'une durée fixe.

Les positions sont initialisées à {x: 0, y: 0} : à la première entrée, les cinq points partent du coin haut-gauche de la fenêtre (mesuré à la frame 0 pour un pointeur en 152, 150 : point 1 en 46, 45 … point 5 en 0, 0). La boucle ne s'arrête jamais — 120 appels rAF/s mesurés hors survol, points cachés — soit dix écritures de style par frame pour rien. Et le lissage est compté en frames : sur un écran 60 Hz, le rattrapage prend deux fois plus de temps en millisecondes qu'à 120 Hz.

Accessibilité

  • Contraste des points (WCAG 1.4.11, seuil 3:1) : #6366f1 à 0,7 d'opacité sur #1a1a24 = 2,5:1, à 0,3 = 1,4:1 — sous le seuil pour tous. La traînée est décorative, mais avec cursor: none le premier point est le seul repère du pointeur : passez-le à opacity: 1 (3,9:1) ou choisissez #a5b4fc (4,9:1 à 0,7).
  • cursor: none masque la flèche alors que le point de tête suit avec retard (30 % par frame) : la position exacte du pointeur n'est jamais affichée. Sur une zone qui contient des cibles à cliquer, gardez la flèche (retirez la règle .cursor-active) et laissez la traînée l'accompagner.
  • Tactile : mesuré avec émulation tactile, un tap dans la zone affiche les cinq points figés et laisse cursor-active posée même après un tap hors zone (pas de mouseleave). Conditionnez l'initialisation à matchMedia('(hover: hover) and (pointer: fine)').matches.
  • prefers-reduced-motion absent : une traînée qui glisse derrière la main est une animation déclenchée par l'interaction (WCAG 2.3.3). Sous @media (prefers-reduced-motion: reduce), masquez les points 2 à 5 (.cursor-trail-v2:not(:first-child) { display: none !important }) ou mettez toutes les vitesses à 1.
  • Lecteurs d'écran et clavier : cinq div vides, pointer-events: none, rien n'est annoncé — ajoutez aria-hidden="true" sur le groupe .cursor-trail-v2-set. Aucun déclenchement au clavier. z-index: 9999 : les points passent au-dessus des modales.

Compatibilité navigateur

Requiert ES2015 (const/let, fonctions fléchées, Array.prototype.some/map), classList, requestAnimationFrame et les variables CSS de la zone. Zéro dépendance.

Chrome 49+✓ Complet
Firefox 45+✓ Complet
Safari 10+✓ Complet
Edge 15+✓ Complet
Mobile iOS✓ Inactif (points figés au tap)
Android Chrome✓ Inactif (points figés au tap)

Sans JavaScript, les cinq points restent en display: none et la flèche système est conservée. Le JS s'arrête proprement si l'un des cinq ids manque (if (trailV2Elements.some(el => !el)) return) : supprimer un point dans le HTML désactive tout l'effet, il faut aussi raccourcir le tableau.

Le code

Structure HTML à coller dans votre page (CSS + JS disponibles avec un compte premium) :

index.html — structure
<div class="cursor-zone" id="zone-trail-v2">
  Survolez cette zone
  <span class="info-text">Trainee fluide en 5 points</span>
</div>
<div class="cursor-trail-v2-set">
  <div class="cursor-trail-v2" id="trailV2-1"></div>
  <div class="cursor-trail-v2" id="trailV2-2"></div>
  <!-- … 5 au total, une par point de traînée … -->
</div>
🔒 Débloquer le code complet — à partir de 2,99 € le 1er mois

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éfautEffet
Vitesses (JS — speed = 0.3 - (i * 0.05)) 0.3 → 0.1 Part de l'écart comblée par frame pour chaque point. Baisser la pente (0.04) allonge la traînée ; monter le premier terme (0.5) colle le point de tête au pointeur.
Nombre de points (HTML — div ; JS — tableau trailV2Elements ; CSS — :nth-child) 5 Les trois doivent concorder : le JS s'arrête si un id manque. Avec 8 points, prolongez la formule (0.3 − i × 0.03) pour que la dernière vitesse reste positive.
Taille (CSS — .cursor-trail-v2 8px) + offset (JS — pos.x - 4) 8 px / −4 Couplées : l'offset doit rester la moitié de la taille pour centrer les points. Des tailles décroissantes par :nth-child donnent une traînée effilée (garder l'offset du plus grand).
Couleur (CSS — .cursor-trail-v2 background) #6366f1 Une seule couleur pour les cinq points. Par :nth-child, vous pouvez dégrader la teinte (indigo → rose) en plus de l'opacité.
Opacités (CSS — .cursor-trail-v2:nth-child(n)) 0,7 · 0,6 · 0,5 · 0,4 · 0,3 Extinction le long de la traînée. Le point 1 à 1 donne un repère net (3,9:1) ; des paliers plus serrés (0,9 → 0,1) rendent la queue quasi invisible.
Position initiale (JS — map(() => ({x: 0, y: 0}))) 0, 0 Cause du départ depuis le coin haut-gauche. Dans mouseenter, réinitialisez trailV2X/Y et chaque pos sur e.clientX/Y.
Arrêt de la boucle (JS — animateTrailV2) permanente Stockez l'identifiant de requestAnimationFrame, annulez-le dans mouseleave avec cancelAnimationFrame, relancez dans mouseenter : zéro travail hors survol.

FAQ

Les cinq positions sont initialisées à (0, 0) et la boucle tourne déjà : au premier mouseenter, les points s'affichent là où ils sont, dans le coin haut-gauche, puis rejoignent le pointeur en cascade — mesuré : point 1 en (46, 45) et point 5 encore en (0, 0) à la frame 0 pour un pointeur en (152, 150). Ajoutez dans mouseenter : trailV2X = e.clientX; trailV2Y = e.clientY; trailV2Positions.forEach(p => { p.x = e.clientX; p.y = e.clientY; }).
Plus longue : baissez les vitesses (chaque point traîne davantage derrière le précédent) ou ajoutez des points — 8 à 10 restent peu coûteux (deux écritures de style par point et par frame). Plus fluide : ne remplacez pas la boucle par une transition CSS sur left/top — relancée 60 fois par seconde, elle ferait ramper la queue (c'est l'effet mesuré sur Dot Follower, fx-0197, où elle double le temps de rattrapage). Écrivez plutôt transform: translate3d() au lieu de left/top pour rester sur le compositeur.
Juste avant </body>, dans leur conteneur .cursor-trail-v2-set (nécessaire aux :nth-child). position: fixed avec left = clientX suppose la fenêtre comme repère : tout ancêtre porteur de transform, filter, perspective, will-change: transform ou contain: paint devient le bloc conteneur et décale la traînée de sa propre position. Le code livré place les div dans la boîte de démo : déplacez-les à la racine dès l'intégration.