Atmosphère✨ Premium

Rain

Un canvas 2D trace 120 gouttes en diagonale par simple addition de pixels, avec anneau de ripple à l'impact — vanilla pur, aucune dépendance.

JSCanvasWeather

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

Hero / Landing — Page de lancement à thème atmosphérique — Rain exemple 1

① Hero / Landing — Page de lancement à thème atmosphérique

QuandLancement d'un jeu de survie, d'une app météo ou d'un SaaS à univers dramatique — la pluie ancre l'atmosphère avant que le visiteur lise le titre.
PourquoiL'effet crée une ambiance immersive sans image réseau : 0 octet chargé, fond <code>#0a0a0f</code>, gouttes à 30 % d'opacité discrètes sous un scrim. Le texte overlay reste prioritaire.
Réglages120 gouttes (défaut), speed: 6 * Math.random() + 4 → cascade dense. Pour une bruine légère en fond de titre SaaS : réduire à 50 gouttes (for (let n = 0; n < 50; n++)) et speed: 3 * Math.random() + 2.
Composant produit — Notification d'alerte météo ou de retard — Rain exemple 2

② Composant produit — Notification d'alerte météo ou de retard

QuandUn dashboard de livraison, de transport ou météo signale une perturbation liée aux précipitations — la pluie en fond de carte contextualise visuellement le message.
PourquoiL'effet remplace une illustration de stock : auto-animé, aucun asset réseau, thématiquement exact. La transparence des gouttes (30 %) laisse le fond de carte lisible.
RéglagesModifier rgba(150,180,220,0.3) en rgba(150,200,180,0.22) pour une teinte verte (pluie printanière) ou réduire à 60 gouttes pour un fond moins chargé derrière les données.
Micro-interaction de conversion — Blocage météo avec réorientation CTA — Rain exemple 3

③ Micro-interaction de conversion — Blocage météo avec réorientation CTA

QuandUne app sport ou outdoor avertit que la session est annulée à cause des précipitations — l'effet confirme visuellement la cause et redirige vers le CTA de reprogrammation.
PourquoiLa cohérence narrative entre le message et le visuel rend l'interruption mémorable et justifiée, réduisant la frustration et augmentant la probabilité de cliquer sur le CTA alternatif.
RéglagesRéduire à 50 gouttes et speed: 4 * Math.random() + 3 pour un effet discret ; ajouter opacity: 0.7 CSS sur le .ps-canvas-wrap et un scrim dense pour que le CTA reste visuellement dominant.

Comment ça marche

La boucle requestAnimationFrame tourne sans interruption — pas d'IntersectionObserver, pas de mécanisme de pause. À chaque frame, le canvas est entièrement recouvert avec #0a0a0f (fillRect plein), ce qui efface la frame précédente sans effet de traîne. Les 120 gouttes sont instanciées au chargement : chaque objet stocke {x, y, len, speed} avec len ∈ [8,23] px et speed ∈ [4,10] px/frame — valeurs fixes par goutte, tirées une seule fois.

Chaque goutte est tracée par un segment d'1 px de (x, y) à (x + 1, y + len). La dérive horizontale fixe de +1 px/frame détermine l'angle de la diagonale : arctan(1/speed), soit ~6–14° selon la vitesse de la goutte. La vitesse est appliquée directement (y += speed, x += 1) sans normalisation par delta-temps — la fluidité dépend donc du taux de rafraîchissement de l'écran. Couleur : rgba(150,180,220,0.3), bleu-gris à 30 % d'opacité.

Quand y > h, la goutte est réinitialisée (y = -len, x aléatoire) et un splash {x, y: h-2, life: 1} est poussé dans un second tableau. Chaque frame : life -= 0.05 sur ~20 frames (~333 ms à 60 fps). Le splash est rendu comme un arc de cercle de rayon 5 × (1 - life) : il grandit de 0 à 5 px tandis que son opacité (0.3 × life) décroît. C'est un anneau de ripple éphémère — pas une accumulation persistante.

L'effet n'implémente ni prefers-reduced-motion, ni ResizeObserver, ni API publique. Le canvas est dimensionné une seule fois au chargement via parentElement.getBoundingClientRect(). L'IIFE cible getElementById('psRain') : conception mono-instance, un canvas par page.

Accessibilité

  • prefers-reduced-motion absent : aucun test window.matchMedia('(prefers-reduced-motion:reduce)') n'est présent — l'animation tourne en permanence, même chez les utilisateurs sensibles au mouvement. À implémenter manuellement dans votre intégration.
  • Le <canvas> ne porte pas aria-hidden="true" dans le code source — les lecteurs d'écran peuvent annoncer un élément vide. Ajoutez cet attribut dans votre HTML d'intégration.
  • Le conteneur .ps-canvas-wrap n'a ni role="img" ni aria-label — l'effet est sémantiquement invisible pour les technologies d'assistance. Ajoutez un libellé descriptif sur l'élément parent.
  • Pas d'élément interactif (clic, focus) : la scène est purement décorative. Aucun problème de navigation au clavier intrinsèque, mais le texte overlay doit rester dans l'ordre de tabulation normal.
  • Contraste overlay : le canvas seul (fond #0a0a0f, gouttes à 30 % d'opacité) n'impose pas de contrainte de contraste propre — ajoutez un scrim semi-opaque si du texte est superposé pour maintenir WCAG AA (ratio ≥ 4,5:1).

Compatibilité navigateur

Nécessite Canvas 2D Context et requestAnimationFrame — supportés dans tous les navigateurs modernes. Zéro dépendance externe.

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

Sans support <code>canvas</code>, le <code>&lt;div&gt;</code> parent reste visible avec son fond — aucune erreur JS fatale, le contenu textuel overlay reste lisible.

Le code

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

index.html — structure
<div class="demo-preview">
  <div class="ps-canvas-wrap" role="img" aria-label="Pluie animée en arrière-plan">
    <canvas class="ps-canvas" id="psRain" aria-hidden="true"></canvas>

    <!-- Facultatif : scrim + contenu overlay -->
    <div class="ps-scrim" aria-hidden="true"></div>
    <div class="ps-content">
      <h2 class="ps-title">Votre message</h2>
      <button class="ps-cta">CTA</button>
    </div>
  </div>
</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
Nombre de gouttes (const 120) 120 Boucle d'init : for (let n = 0; n < 120; n++). De 40 (bruine) à 200 (orage dense) — au-delà de 250, des ralentissements apparaissent sur mobile bas de gamme.
Vitesse par goutte (speed: 6×r+4) 4–10 px/frame Remplacer 6 * Math.random() + 4 : 3 * Math.random() + 2 = bruine lente, 10 * Math.random() + 8 = orage violent. Non normalisé par delta-temps : dépend du taux de rafraîchissement.
Longueur de traînée (len: 15×r+8) 8–23 px Remplacer 15 * Math.random() + 8 : traînées courtes (4 + 4 * Math.random()) = pluie fine ; longues (20 + 20 * Math.random()) = averse torrentielle.
Dérive horizontale (e.x += 1) 1 px/frame La ligne e.x += 1 fixe l'angle de la diagonale. Augmenter à 2–3 = vent latéral fort ; mettre à 0 = chute verticale pure ; valeur négative = pluie venant de droite.
Couleur des gouttes (rgba) rgba(150,180,220,0.3) Modifier couleur et opacité inline dans la boucle : rgba(220,230,255,0.5) = pluie froide brillante, rgba(100,130,100,0.3) = orage verdâtre, opacité 0,15 = fond très discret.
Rayon max du splash (5) 0–5 px Modifier 5 * (1 - c.life) : 8–12 px = impact visible sur grand écran ; 2–3 px = frémissement léger. Durée du ripple : contrôlée par le décrément life -= 0.05 (20 frames ≈ 333 ms).

FAQ

Le code actuel ne contient pas d'IntersectionObserver. Pour l'ajouter : déclarez un flag let active = true avant l'IIFE, observez le .ps-canvas-wrap et basculez active selon l'intersection. Dans la boucle, remplacez requestAnimationFrame(c) par if (active) requestAnimationFrame(c); else cancelAnimationFrame(rafId).
L'IIFE cible getElementById('psRain') — un seul canvas par page par défaut. Pour plusieurs instances, extrayez la logique dans une fonction initRain(id) contenant les tableaux drops et splashes en closure, puis appelez-la pour chaque canvas avec un id distinct ('psRain1', 'psRain2', etc.). La fonction globale setupCanvas(id) définie hors de l'IIFE est réutilisable directement.
Non dans l'implémentation actuelle. Pour y remédier, ajoutez avant le lancement de la boucle : if (window.matchMedia('(prefers-reduced-motion:reduce)').matches) return;. Vous pouvez aussi dessiner une frame statique (quelques gouttes fixes) avant de sortir, pour conserver la présence visuelle sans animation continue.