Grain Gradient
Canvas 2D régénère du bruit aléatoire pixel par pixel à chaque frame, superposé en soft-light sur gradient sombre — grain animé, zéro dépendance.
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. Backgrounds comprend 50 effets, dont 6 gratuits. Découvrir la catégorie →
3 exemples d'usage



Comment ça marche
L'animation repose sur la manipulation directe de pixels via ImageData. À chaque frame, ctx.createImageData(w, h) alloue un tampon de w × h × 4 octets. La boucle itère sur chaque pixel et écrit une valeur aléatoire v = Math.random() * 40 dans les canaux R, G et B (grain monochrome), avec un alpha fixe à 35/255 ≈ 14 %. Le tampon est rendu en une seule passe ctx.putImageData(), puis requestAnimationFrame rappelle immédiatement la fonction — chaque frame est donc entièrement nouvelle, sans persistance de la précédente.
La couche de grain est positionnée au-dessus du dégradé CSS (linear-gradient(145deg, #0f172a → #7c3aed)) avec mix-blend-mode: soft-light. Ce mode de fusion préserve les ombres profondes tout en éclaircissant les tons intermédiaires — le grain paraît organique et intégré plutôt que plaqué. L'opacité globale de la couche est fixée à 0,35 via CSS ; les deux paramètres (blend-mode et opacity) agissent en tandem pour doser la visibilité du grain.
Le canvas se redimensionne dynamiquement : resize() lit les dimensions du parent via getBoundingClientRect() et met à jour canvas.width / canvas.height à chaque événement resize. Le nouveau tampon ImageData est alloué aux dimensions courantes à chaque frame — aucun artefact d'étirement même après un changement de taille du conteneur.
Accessibilité
- prefers-reduced-motion : absent du code — le RAF tourne en continu même si l'OS demande à réduire les animations. Pour les intégrations accessibles, ajoutez
if (matchMedia('(prefers-reduced-motion:reduce)').matches) return;avant le premier appel àdrawGrain(). - Le
<canvas>ne porte pasaria-hidden="true"dans le code original — les lecteurs d'écran peuvent annoncer un élément canvas vide. Recommandé : ajouteraria-hidden="true"sur le canvas. - Le contenu overlay (
.ng-graingr-content) est dans le flux DOM normal : titres et éléments texte sont lisibles par les lecteurs d'écran indépendamment du canvas. - Aucun élément interactif dans l'effet — pas de problème de navigation au clavier ni de focus trap.
- Contraste texte sur gradient sombre : le fond
#0f172a → #7c3aeddonne un ratio > 4,5:1 avec du texte blanc, conforme WCAG AA.
Compatibilité navigateur
Nécessite Canvas 2D Context, ImageData et requestAnimationFrame — supportés dans tous les navigateurs modernes depuis 2015.
Si <code>canvas</code> n'est pas supporté ou si le contexte 2D échoue (mode économie d'énergie GPU), la fonction retourne silencieusement — le dégradé CSS reste visible en fond.
Le code
Structure HTML à coller dans votre page (CSS + JS disponibles avec un compte premium) :
<div class="ng-graingr-scene">
<div class="ng-graingr-bg"></div>
<canvas class="ng-graingr-noise" id="ngGrainCanvas" width="320" height="220"
aria-hidden="true"></canvas>
<!-- Facultatif : contenu overlay -->
<div class="ng-graingr-content">
<div class="ng-graingr-circle">
<svg viewBox="0 0 24 24" aria-hidden="true">
<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"></polygon>
</svg>
</div>
<h3>Votre titre</h3>
</div>
</div>
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éfaut | Effet |
|---|---|---|
| opacity: .35 (.ng-graingr-noise) | 0.35 | Intensité globale de la couche grain. 0.20 = très discret, 0.55 = grain affirmé. |
| mix-blend-mode (.ng-graingr-noise) | soft-light | Mode de fusion du grain sur le gradient. overlay = contraste fort, luminosity = grain neutre en couleur, screen = grain lumineux. |
| background (.ng-graingr-bg) | linear-gradient(145deg, #0f172a, #7c3aed) | Gradient de fond — changez les couleurs et l'angle (ex. 90deg) pour votre palette brand. |
| Math.random() * 40 (JS, drawGrain) | 40 | Amplitude du bruit : valeur max des pixels grain (0–255). 20 = grain fin et subtil, 80 = grain grossier et contrasté. |
| data[i+3] = 35 (JS, drawGrain) | 35 | Alpha de chaque pixel grain (0–255). 20 = quasi-transparent, 80 = grain opaque. Agit en conjonction avec l'opacity CSS. |
| border-radius (.ng-graingr-scene) | 16px | Arrondi des coins de la scène. 0 = plein écran sans arrondi, 24px = look card prononcé. |
FAQ
createPattern() + fillRect() pour couvrir la grande surface..ng-graingr-bg (background: linear-gradient(…)). Modifiez les couleurs, l'angle ou ajoutez des stops. Le canvas de grain est transparent et se superpose en soft-light par-dessus, quel que soit le gradient.id unique (ngGrainCanvas). Pour plusieurs instances, extrayez la logique dans une fonction réutilisable : function initGrain(canvas) { var ctx = canvas.getContext('2d'); … } et appelez-la pour chaque canvas. L'effet est stateless par frame — aucune variable globale à partager entre instances.