BackgroundsGratuit

Floating Particles

30 disques CSS montent en boucle depuis le bas du conteneur — position, délai, durée, taille et couleur aléatoires à l'injection, zéro canvas, zéro dépendance.

JSParticlesLoop
Particles
Survolez ou cliquez la scène pour interagir

Cet effet est gratuit — la catégorie Backgrounds en contient 50 au total, dont 6 gratuits. Effect.Labs regroupe 811 effets vanilla. Découvrir la catégorie →

Exemples d'usage

① Fond de hero — Landing page tech en dark mode

QuandLa page d'accueil d'un SaaS, d'un portfolio ou d'un outil dev veut un arrière-plan animé discret sur toute la hauteur du viewport.
PourquoiLes particules couvrent uniformément une grande surface grâce à la distribution aléatoire de la position horizontale et du délai — aucune zone vide, aucun pic de densité visible. Le fond sombre laisse le contenu texte primer sans compétition.
Réglages30 particules, palette indigo/violet/fuchsia/cyan par défaut. Passer translateY(-100vh) en lieu de -350px si le viewport est plus haut que 350 px.

② Page de succès — Confirmation d'inscription ou de paiement

QuandL'utilisateur vient de finaliser une action clé (création de compte, achat, abonnement) et arrive sur un écran de confirmation pleine largeur.
PourquoiLes 30 particules en montée continue couvrent toute la surface et imitent un effet confettis minimaliste — elles récompensent visuellement l'utilisateur sans animation lourde ni librairie de confettis. La boucle fluide CSS évite tout à-coup.
Réglages30 particules, palette complète (indigo/violet/fuchsia/cyan), opacité 0,4–0,9 (0.4 + Math.random() * 0.5), translateY(-400px) pour un mouvement ample sur un viewport typique pleine hauteur.

③ Lobby ou menu principal — Jeu casual ou application indie

QuandL'interface dark d'un jeu casual ou d'une app indie affiche le menu principal ou un salon d'attente et veut une ambiance animée sans sacrifier les performances.
PourquoiLes particules montantes en boucle infinie remplacent une vidéo de fond (lourde) ou un canvas WebGL (complexe) par du CSS pur. La lenteur des cycles (10–20 s) rend l'animation imperceptible en termes de performance et laisse la typographie du menu totalement lisible.
Réglages20 particules, palette violet/fuchsia (['#8b5cf6', '#d946ef']), cycles lents (10 + Math.random() * 10 → 10–20 s), opacité basse (0.15 + Math.random() * 0.45), translateY(-400px).

Comment ça marche

Un IIFE JavaScript cible le conteneur par getElementById('particlesBg') et injecte 30 <div class="particle"> dans le DOM au chargement de la page. Chaque particule reçoit des styles inline calculés une seule fois : position horizontale aléatoire (left 0–100 %), délai de départ (animationDelay 0–10 s), durée de cycle (animationDuration 5–15 s), taille (width/height 2–6 px) et opacité initiale (0,3–1,0). La couleur est tirée aléatoirement d'un tableau de 4 teintes : #6366f1, #8b5cf6, #d946ef, #06b6d4.

L'animation CSS @keyframes float tourne en boucle infinite sur chaque particule. Elle part de translateY(0) rotate(0deg) et arrive à translateY(-350px) rotate(720deg) — 350 px vers le haut et deux tours complets. L'opacité passe de 0 à 1 entre 0 % et 10 % du cycle (fondu d'apparition), reste à 1 de 10 % à 90 %, puis retombe à 0 (fondu de sortie). Le bottom: -20px sur .particle garantit que chaque disque émerge de sous le bord inférieur du conteneur.

Le conteneur .bg-particles utilise position: relative; overflow: hidden — les particules qui dépassent le haut ou les côtés sont clippées sans débordement. Ni requestAnimationFrame, ni canvas : toute la cinématique est déléguée au compositor CSS du navigateur, ce qui assure des animations fluides sans bloquer le thread JS principal.

Accessibilité

  • Pas de prefers-reduced-motion : le code ne détecte pas cette préférence OS — l'animation tourne en boucle infinie pour tous les utilisateurs. Pour y remédier, ajoutez @media (prefers-reduced-motion: reduce) { .particle { animation: none; opacity: 0; } } dans le CSS.
  • Le conteneur .bg-particles n'a ni role ni aria-label — les lecteurs d'écran ignorent la zone. Acceptable pour un fond purement décoratif ; si du contenu est présent en overlay, balisez-le séparément.
  • Le .bg-label centré (texte blanc sur fond rgb(10,10,15)) offre un ratio de contraste supérieur à 7:1 (niveau AAA WCAG), mais tout texte overlay personnalisé doit être vérifié indépendamment.
  • Aucune interaction clavier ni zone focusable — l'effet est 100 % décoratif. Si vous ajoutez un bouton en overlay, veillez à ce qu'il reste dans le flux de tabulation normal.
  • Les particules sont des cercles CSS légers. La rotation à 720° (deux tours complets) peut toutefois être perceptible pour des utilisateurs sensibles au mouvement vestibulaire — l'absence de détection prefers-reduced-motion reste la limite principale de l'effet.

Compatibilité navigateur

Nécessite les animations CSS et les transforms 2D — supportés nativement dans tous les navigateurs modernes sans préfixe. Zéro dépendance externe.

Chrome 88+✓ Complet
Firefox 87+✓ Complet
Safari 15+✓ Complet
Edge 88+✓ Complet
Mobile iOS✓ Complet
Android Chrome✓ Complet

Si les animations CSS ne sont pas supportées, les particules restent positionnées à <code>bottom: -20px</code> sous le conteneur, invisibles et sans erreur JS. Le contenu overlay reste intact et lisible.

Le code

Copiez les trois blocs dans votre page. Aucune dépendance.

HTML
<div class="bg-particles" id="particlesBg" style="width:100%;min-height:300px;">
  <span class="bg-label">Particles</span>
  <div class="particle" style="left: 81.3473%; animation-delay: 2.23608s; animation-duration: 5.2817s; width: 4.22835px; height: 4.22835px; opacity: 0.955616; background: rgb(99, 102, 241);">
  </div>
  <div class="particle" style="left: 70.7537%; animation-delay: 0.241083s; animation-duration: 7.42418s; width: 5.65692px; height: 5.65692px; opacity: 0.92056; background: rgb(139, 92, 246);">
  </div>
  <div class="particle" style="left: 75.672%; animation-delay: 4.05243s; animation-duration: 12.6442s; width: 4.03745px; height: 4.03745px; opacity: 0.613098; background: rgb(217, 70, 239);">
  </div>
  <div class="particle" style="left: 23.7548%; animation-delay: 6.59898s; animation-duration: 7.30182s; width: 4.68637px; height: 4.68637px; opacity: 0.997694; background: rgb(139, 92, 246);">
  </div>
  <div class="particle" style="left: 44.7656%; animation-delay: 7.28707s; animation-duration: 8.80555s; width: 5.90259px; height: 5.90259px; opacity: 0.310997; background: rgb(6, 182, 212);">
  </div>
  <div class="particle" style="left: 81.7612%; animation-delay: 8.81586s; animation-duration: 7.87704s; width: 3.18595px; height: 3.18595px; opacity: 0.642642; background: rgb(217, 70, 239);">
  </div>
  <div class="particle" style="left: 78.4019%; animation-delay: 3.56918s; animation-duration: 12.7866s; width: 5.32692px; height: 5.32692px; opacity: 0.562289; background: rgb(217, 70, 239);">
  </div>
  <div class="particle" style="left: 31.7758%; animation-delay: 8.78552s; animation-duration: 14.4494s; width: 3.18608px; height: 3.18608px; opacity: 0.947093; background: rgb(217, 70, 239);">
  </div>
  <div class="particle" style="left: 5.26617%; animation-delay: 0.0824003s; animation-duration: 9.79734s; width: 5.93249px; height: 5.93249px; opacity: 0.311894; background: rgb(217, 70, 239);">
  </div>
  <div class="particle" style="left: 83.6788%; animation-delay: 1.18016s; animation-duration: 5.3337s; width: 2.83547px; height: 2.83547px; opacity: 0.927981; background: rgb(217, 70, 239);">
  </div>
  <div class="particle" style="left: 51.7278%; animation-delay: 3.86724s; animation-duration: 7.14767s; width: 3.37888px; height: 3.37888px; opacity: 0.968284; background: rgb(217, 70, 239);">
  </div>
  <div class="particle" style="left: 7.70877%; animation-delay: 5.27914s; animation-duration: 7.62976s; width: 3.64616px; height: 3.64616px; opacity: 0.972167; background: rgb(139, 92, 246);">
  </div>
  <div class="particle" style="left: 23.1152%; animation-delay: 7.74466s; animation-duration: 12.5337s; width: 3.69188px; height: 3.69188px; opacity: 0.505243; background: rgb(139, 92, 246);">
  </div>
  <div class="particle" style="left: 95.7918%; animation-delay: 1.96144s; animation-duration: 7.13189s; width: 3.18404px; height: 3.18404px; opacity: 0.81407; background: rgb(217, 70, 239);">
  </div>
  <div class="particle" style="left: 80.5541%; animation-delay: 5.05999s; animation-duration: 14.565s; width: 4.36892px; height: 4.36892px; opacity: 0.551264; background: rgb(99, 102, 241);">
  </div>
  <div class="particle" style="left: 22.2578%; animation-delay: 0.454724s; animation-duration: 8.57647s; width: 5.41375px; height: 5.41375px; opacity: 0.686757; background: rgb(99, 102, 241);">
  </div>
  <div class="particle" style="left: 8.84408%; animation-delay: 2.93561s; animation-duration: 8.89404s; width: 4.54025px; height: 4.54025px; opacity: 0.65617; background: rgb(6, 182, 212);">
  </div>
  <div class="particle" style="left: 62.9086%; animation-delay: 9.74476s; animation-duration: 8.75279s; width: 4.68559px; height: 4.68559px; opacity: 0.927903; background: rgb(217, 70, 239);">
  </div>
  <div class="particle" style="left: 39.373%; animation-delay: 3.33201s; animation-duration: 6.02767s; width: 2.17088px; height: 2.17088px; opacity: 0.937757; background: rgb(6, 182, 212);">
  </div>
  <div class="particle" style="left: 31.1378%; animation-delay: 0.0207585s; animation-duration: 8.18352s; width: 4.40257px; height: 4.40257px; opacity: 0.847564; background: rgb(139, 92, 246);">
  </div>
  <div class="particle" style="left: 70.8041%; animation-delay: 9.84913s; animation-duration: 6.34645s; width: 5.64475px; height: 5.64475px; opacity: 0.399727; background: rgb(217, 70, 239);">
  </div>
  <div class="particle" style="left: 63.0477%; animation-delay: 1.59297s; animation-duration: 10.5432s; width: 5.17464px; height: 5.17464px; opacity: 0.571377; background: rgb(217, 70, 239);">
  </div>
  <div class="particle" style="left: 13.5519%; animation-delay: 2.21412s; animation-duration: 8.68294s; width: 5.68967px; height: 5.68967px; opacity: 0.653604; background: rgb(139, 92, 246);">
  </div>
  <div class="particle" style="left: 23.2941%; animation-delay: 5.13453s; animation-duration: 9.1288s; width: 4.0929px; height: 4.0929px; opacity: 0.729983; background: rgb(99, 102, 241);">
  </div>
  <div class="particle" style="left: 47.6701%; animation-delay: 2.03842s; animation-duration: 10.9313s; width: 3.66998px; height: 3.66998px; opacity: 0.646271; background: rgb(139, 92, 246);">
  </div>
  <div class="particle" style="left: 5.5714%; animation-delay: 3.88957s; animation-duration: 13.6884s; width: 4.12863px; height: 4.12863px; opacity: 0.554226; background: rgb(217, 70, 239);">
  </div>
  <div class="particle" style="left: 62.4054%; animation-delay: 6.76345s; animation-duration: 12.4475s; width: 4.30277px; height: 4.30277px; opacity: 0.932268; background: rgb(139, 92, 246);">
  </div>
  <div class="particle" style="left: 16.994%; animation-delay: 5.42798s; animation-duration: 8.73918s; width: 3.54539px; height: 3.54539px; opacity: 0.836459; background: rgb(6, 182, 212);">
  </div>
  <div class="particle" style="left: 39.5805%; animation-delay: 6.84787s; animation-duration: 11.154s; width: 5.40263px; height: 5.40263px; opacity: 0.705239; background: rgb(99, 102, 241);">
  </div>
  <div class="particle" style="left: 32.2585%; animation-delay: 2.6477s; animation-duration: 7.11463s; width: 3.95658px; height: 3.95658px; opacity: 0.871536; background: rgb(6, 182, 212);">
  </div>
</div>
CSS
.bg-particles  {
   position: relative;
   overflow: hidden;
   background: rgb(10, 10, 15);
   }

.particle  {
   position: absolute;
   bottom: -20px;
   width: 4px;
   height: 4px;
   background: rgb(99, 102, 241);
   border-radius: 50%;
   animation: 10s ease 0s infinite normal none running float;
   }

@keyframes float  {
   
  0%  {
   transform: translateY(0px) rotate(0deg);
   opacity: 0;
   }
  10%  {
   opacity: 1;
   }
  90%  {
   opacity: 1;
   }
  100%  {
   transform: translateY(-350px) rotate(720deg);
   opacity: 0;
   }
}

.bg-label  {
   position: absolute;
   top: 50%;
   left: 50%;
   transform: translate(-50%, -50%);
   font-weight: 700;
   font-size: 1.5rem;
   color: white;
   text-shadow: rgba(0, 0, 0, 0.5) 0px 2px 10px;
   z-index: 10;
   }
JavaScript (fx-0052)
// Generate particles
    (function() {
      var el = document.getElementById('particlesBg');
      if (!el) return;
      var colors = ['#6366f1', '#8b5cf6', '#d946ef', '#06b6d4'];
      for (var i = 0; i < 30; i++) {
        var particle = document.createElement('div');
        particle.className = 'particle';
        particle.style.left = Math.random() * 100 + '%';
        particle.style.animationDelay = Math.random() * 10 + 's';
        particle.style.animationDuration = (5 + Math.random() * 10) + 's';
        particle.style.width = (2 + Math.random() * 4) + 'px';
        particle.style.height = particle.style.width;
        particle.style.opacity = 0.3 + Math.random() * 0.7;
        particle.style.background = colors[Math.floor(Math.random() * colors.length)];
        el.appendChild(particle);
      }
    })();

Personnaliser

Options passées à l'API ou attributs data-* :

Option / propriétéDéfautEffet
colors (tableau JS) ['#6366f1','#8b5cf6','#d946ef','#06b6d4'] Palette de couleurs des particules. Remplacez par votre palette brand — toute valeur CSS de couleur est acceptée.
i < 30 (boucle JS) 30 Nombre de particules générées. 15–20 pour un fond léger, 40–60 pour une densité élevée (performances desktop uniquement).
animationDuration (JS) 5 + Math.random() * 10 → 5–15 s Plage de durée d'un cycle complet. Augmentez la base (ex. 8+) pour des particules plus lentes et contemplatives.
animationDelay (JS) Math.random() * 10 → 0–10 s Délai maximal avant le premier départ. Augmentez à 15–20 s pour un étalement plus progressif au chargement.
width / height (JS) 2 + Math.random() * 4 → 2–6 px Plage de taille des disques. Augmentez (ex. 4 + Math.random() * 8) pour des particules plus visibles sur grands écrans.
opacity (JS) 0.3 + Math.random() * 0.7 → 0.3–1.0 Fourchette d'opacité initiale. Réduisez à 0.15–0.5 pour un fond très discret, augmentez vers 0.8–1.0 pour un effet affirmé.
translateY (CSS @keyframes float) -350px Distance parcourue vers le haut. Passez à -100vh pour couvrir la hauteur exacte du conteneur quelle qu'elle soit.
background (CSS .bg-particles) rgb(10, 10, 15) Couleur de fond du conteneur. Passez à transparent pour superposer les particules à votre propre background.

FAQ

Peut-on afficher plusieurs instances de Floating Particles sur la même page ?

Le script IIFE cible l'id fixe particlesBg — une seule instance par défaut. Pour plusieurs zones, dupliquez le bloc JS en changeant l'id ciblé (getElementById('particlesBg2')) et l'id du conteneur HTML correspondant. Les classes CSS .bg-particles et .particle restent communes — pas besoin de les dupliquer.

L'effet respecte-t-il prefers-reduced-motion ?

Non, le code actuel ne détecte pas cette préférence. Pour y remédier, ajoutez ce bloc CSS : @media (prefers-reduced-motion: reduce) { .particle { animation: none; opacity: 0; } }. Les particules sont simplement masquées plutôt qu'animées — le fond reste sombre et le contenu overlay est intact.

Combien de particules peut-on afficher sans dégradation de performance ?

Les animations CSS sont gérées par le compositor du navigateur (thread séparé du JS), donc 30–60 particules restent fluides à 60 fps sur desktop. Sur mobile, limitez à 15–25 pour éviter une surchauffe GPU. La durée de l'animation (animationDuration) n'a pas d'impact sur la performance — seul le nombre de nœuds DOM compte.