Atmosphère✨ Premium

Ripple Effect

Onde circulaire Material Design créée au point de clic — zéro rAF, positionnement relatif, animation CSS pure scale+opacité, auto-nettoyage sur animationend.

JSMaterial

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 — Zone interactive de bienvenue — Ripple Effect exemple 1

① Hero / Landing — Zone interactive de bienvenue

QuandSur une landing page où l'utilisateur doit explorer ou cliquer n'importe où pour démarrer — onboarding, page d'accueil produit, splash screen.
PourquoiL'onde confirme chaque clic sur la zone hero et renforce la réactivité perçue sans charger la page d'animations autonomes — le fond reste lisible.
RéglagesCouleur de l'onde : rgba(99,102,241,0.35) (violet brand) ; scale final : 8× ; durée : 0.8s ease-out. Conteneur pleine largeur avec fond dégradé indigo.
Composant produit — Carte d'action dashboard — Ripple Effect exemple 2

② Composant produit — Carte d'action dashboard

QuandSur un tableau de bord ou une liste de tâches où chaque carte est cliquable pour ouvrir un détail, filtrer ou déclencher une action.
PourquoiL'onde localisée indique quel élément exact l'utilisateur a activé dans une liste dense — feedback de sélection sans changement brutal de couleur.
RéglagesCouleur de l'onde : rgba(255,255,255,0.18) sur fond sombre ; scale : 6× ; durée : 0.55s. Carte avec border-radius: 16px et overflow: hidden.
Micro-interaction de conversion — Bouton CTA principal — Ripple Effect exemple 3

③ Micro-interaction de conversion — Bouton CTA principal

QuandSur le bouton « S'abonner », « Acheter » ou « Démarrer l'essai » — l'onde se propage depuis le point de clic avant que la page redirige.
PourquoiL'animation CSS (0 rAF) ne bloque pas la redirection JS : l'onde part, le <code>setTimeout</code> ou la navigation s'exécutent dans le même tick. Le feedback précède la latence réseau.
RéglagesCouleur de l'onde : rgba(255,255,255,0.50) sur bouton violet ; scale : 5× ; durée : 0.5s. Conteneur = le <button> lui-même avec position: relative; overflow: hidden.

Comment ça marche

Au clic, getBoundingClientRect() convertit les coordonnées écran (clientX/Y) en coordonnées locales au conteneur. La soustraction clientX - rect.left donne la position exacte même si le conteneur est transformé CSS ou que la page est scrollée.

Un <div class="ripple"> est créé et inséré dans le conteneur à ces coordonnées. Sa taille est fixée à 100 × 100 px directement en JS ; il est centré sur le point de clic via marginLeft: -50px; marginTop: -50px. Le conteneur porte overflow: hidden — l'onde est clippée à ses bords, donnant l'illusion qu'elle émerge de l'intérieur du composant.

Toute l'animation est portée par une keyframe CSS (scale(0) → scale(N) + opacity 0.4 → 0) : aucun requestAnimationFrame ne tourne, aucune boucle JS n'est lancée. Le thread principal n'est pas bloqué. Plusieurs clics rapprochés créent plusieurs ondes .ripple indépendantes dans le DOM simultanément.

L'écouteur animationend supprime l'élément du DOM dès que la keyframe se termine — aucun timer, aucun nettoyage manuel. À noter : la classe .ripple et la keyframe CSS ne sont pas définies dans le CSS fourni (elles provenaient d'une page hôte) ; elles doivent être ajoutées à votre feuille de style. Les éléments .ripple nécessitent aussi pointer-events: none pour ne pas capturer les clics suivants.

Accessibilité

  • prefers-reduced-motion absent : le code ne vérifie pas la préférence système — l'animation tourne toujours. Ajoutez @media (prefers-reduced-motion: reduce) { .ripple { animation-duration: 0.01ms !important; } } pour que animationend se déclenche quasi-instantanément sans bloquer le nettoyage DOM.
  • Le .ripple-container a cursor: pointer mais pas de tabindex="0" ni de role="button" — non activable au clavier dans l'état fourni. Ajoutez les deux attributs et un listener keydown (Enter / Espace) si l'élément est interactif.
  • Aucun aria-label sur le conteneur dans le code d'origine. Si le texte intérieur ne décrit pas l'action clairement, ajoutez un libellé ARIA explicite.
  • Les éléments .ripple injectés ne portent pas pointer-events: none dans le CSS fourni — à ajouter pour éviter qu'une onde en cours capture les clics suivants et les empêche de déclencher leur propre onde.
  • Le fond #12121a avec texte blanc dépasse WCAG AA (ratio > 10:1) — pas de problème de contraste sur la configuration par défaut.

Compatibilité navigateur

Utilise getBoundingClientRect(), addEventListener('animationend') et manipulation DOM — universels depuis Chrome 43 / Firefox 43 / Safari 9.

Chrome 43+✓ Complet
Firefox 43+✓ Complet
Safari 9+✓ Complet
Edge 79+✓ Complet
Mobile iOS 9+✓ Touch OK
Android Chrome 43+✓ Complet

Si les animations CSS ne sont pas supportées, <code>animationend</code> ne se déclenche jamais et les <code>.ripple</code> restent dans le DOM. Ajoutez un <code>setTimeout</code> de secours à 1 s pour les retirer.

Le code

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

index.html — structure
<div class="ripple-container" id="rippleContainer">
  <!-- Contenu du composant (texte, icône, libellé) -->
  Cliquez ici
  <!-- Les <div class="ripple"> sont injectés par le JS au clic et supprimés sur animationend -->
</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
background (CSS .ripple) rgba(255,255,255,0.4) Couleur et opacité de l'onde. Utilisez la couleur brand avec une opacité 0.2–0.5 selon le contraste du fond.
animation-duration (CSS .ripple) ~0.6s Durée de l'expansion. 0.4s = snappy (bouton CTA), 0.8–1s = organique (hero, surfaces larges).
to { transform: scale(N) } (CSS @keyframes) 4 Facteur d'expansion final. Calibrez selon la taille du conteneur : N ≈ (2 × diagonale du conteneur) ÷ 100 pour que l'onde couvre l'intégralité de la surface.
ripple.style.width / height (JS lignes 7–8) 100px Taille initiale du disque. Augmenter adoucit le départ de l'onde ; réduire la rend plus ponctuelle. Ajustez toujours marginLeft = marginTop = -(taille / 2).
animation-timing-function (CSS .ripple) ease-out Easing de l'expansion. ease-out = départ vif, fin douce (Material Design). cubic-bezier(0.4,0,0.2,1) = courbe Material standard.
border-radius (CSS .ripple) 50% Forme de l'onde. 50% = cercle parfait. Réduire donne un losange arrondi ; 0 = onde carrée pour un rendu plus géométrique.

FAQ

Oui. Chaque clic crée un nouvel élément .ripple indépendant dans le conteneur. Plusieurs clics rapprochés génèrent des ondes qui se chevauchent — chacune se supprime individuellement sur son propre animationend.
Ajoutez dans votre CSS : @media (prefers-reduced-motion: reduce) { .ripple { animation-duration: 0.01ms !important; } }. L'onde se termine quasi-instantanément, animationend se déclenche normalement et nettoie le DOM. Aucune modification JS nécessaire.
Oui. Ajoutez position: relative; overflow: hidden sur le <button> — le comportement natif (focus, clavier, submit) est préservé puisque l'effet se contente d'insérer un élément enfant sans toucher aux événements.