Backgrounds✨ Premium

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.

CanvasJSGradient

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

Hero plein écran — Landing page produit dark — Grain Gradient exemple 1

① Hero plein écran — Landing page produit dark

QuandLa page d'accueil ou de produit adopte un thème sombre et cherche un fond qui vit sans être distrayant — SaaS, portfolio, agence créative.
PourquoiLe grain animé ajoute de la profondeur et de la texture à un gradient qui serait autrement plat. Il attire l'œil sans concurrencer le titre ni le CTA, car le mouvement est subliminal.
Réglagesopacity: .35 sur .ng-graingr-noise (abaisser à .20 pour plus de sobriété), gradient aux couleurs brand, scène en 100vw × 100vh.
Carte premium — Badge d'offre dans un dashboard dark — Grain Gradient exemple 2

② Carte premium — Badge d'offre dans un dashboard dark

QuandUn composant card dans un dashboard ou une page pricing avec thème sombre doit ressortir visuellement parmi des cartes plates.
PourquoiLe grain en soft-light sur fond violet profond donne à la carte une qualité tactile proche d'un matériau de luxe — sans image ni SVG lourd. L'initialisation se fait sur l'id du canvas dans la carte.
RéglagesScène réduite (320×220), gradient vers votre couleur accent, mix-blend-mode: overlay pour un grain plus affirmé, opacity: .45.
Fond de lecteur audio — Écran de lecture dark dans une app musicale — Grain Gradient exemple 3

③ Fond de lecteur audio — Écran de lecture dark dans une app musicale

QuandL'écran de lecture d'une app musicale affiche une longue session d'écoute avec du contenu statique (pochette, titre, contrôles) sur un fond sombre — l'interface risque de paraître figée entre les interactions.
PourquoiLe grain Canvas régénéré à chaque frame garantit qu'aucune frame n'est identique : le fond vit en silence derrière les contrôles du lecteur, rendant l'interface organique sans distraire l'écoute. Le mouvement continu et imperceptible crée la sensation d'une texture vivante sur de longues sessions.
RéglagesGradient sombre centré sur la couleur dominante de la pochette (ex. #0d0d18 → #1a0a2e), amplitude grain à 30 (changer * 40* 30 dans drawGrain) pour rester subtil, opacity: .30 sur .ng-graingr-noise, scène couvre l'ensemble du conteneur.

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 pas aria-hidden="true" dans le code original — les lecteurs d'écran peuvent annoncer un élément canvas vide. Recommandé : ajouter aria-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 → #7c3aed donne 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.

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

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) :

index.html — structure
<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>
🔒 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
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

Sur de petites surfaces (320×220 px ≈ 70 000 pixels), l'allocation et l'écriture du tampon prennent < 1 ms sur du matériel actuel — imperceptible. Pour des surfaces > 800×600, préférez une approche tilesample : générez un petit canvas grain (ex. 256×256) toutes les 2–3 frames et répliquez-le via createPattern() + fillRect() pour couvrir la grande surface.
Oui — le gradient est entièrement dans le CSS de .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.
Le code d'origine cible un 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.