Distortion✨ Premium

Noise Overlay

Film grain that shivers on any surface: an SVG noise layer at 15% shifts by one pixel every 20 ms, without a single line of JavaScript.

CSSFilmTexture

Updated

This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. Distortion has 31 effects, including 5 free. Explore the category →

3 usage examples

Film club home page — silver grain over the whole opening picture — Noise Overlay example 1

① Film club home page — silver grain over the whole opening picture

WhenThe Vossandre film club opens its site on a dusk landscape; the grain shivers across the full width, under the title, the menu and the “See the programme” button.
WhyThe grain says “film stock” before anyone reads the title. Because it runs under the content, the text stays crisp and the button clickable.
Settings--fgr-w: 100%, --fgr-h: 100%, --fgr-radius: 0, --fgr-opacity: .45; --fgr-bg = the landscape drawn with CSS gradients (a photo via url() works the same). Menu and title live in .fgr-content.
Vinyl sleeve on a record shop's product page — Noise Overlay example 2

② Vinyl sleeve on a record shop's product page

WhenOn the Kestrombe album page at the Brumelac record shop, the square sleeve keeps a living grain next to the track list, the price and the buy button.
WhyA flat artwork looks printed and aged as soon as it gets grain. The effect gives texture to a vector illustration without editing the image.
Settings--fgr-w and --fgr-h at 206px, --fgr-radius: 2px, --fgr-opacity: .5, --fgr-root-bg: transparent, --fgr-root-h: 206px; band and album names sit in .fgr-content, the surface carries role="img".
“Grain” slider in a photo editor — the setting applied live — Noise Overlay example 3

③ “Grain” slider in a photo editor — the setting applied live

WhenIn the Lumaquet editor, the user drags the “Grain” slider of the Film look panel; the photo preview gets more or less grainy at the same moment.
WhyGrain strength is a plain CSS variable: wiring it to an input type="range" gives an instant preview, with no image recomputed.
Settings300×220 px preview; the slider (0 to 70) writes --fgr-opacity from 0 to .70 on the root. For the capture, the scene moves the slider back and forth until someone touches it.

How it works

The surface .fgr-box (250×150 px by default, indigo to violet gradient) holds two children: the .fgr-grain layer and your own .fgr-content. The layer is an SVG image embedded as data:: an feTurbulence filter of type fractalNoise (frequency 0.8, 4 octaves) that yields a fine coloured noise. No external image is loaded.

The grain comes alive through the fgr-move animation: over 0.2 s and 10 steps (steps(10)), the layer slides 10 px up and left, then the loop starts again. The pattern therefore jumps one pixel every 20 ms, like the grain of running film stock. The layer overhangs by 10 px on the right and bottom so this slide never uncovers a bare strip at the edge.

The .fgr-content sits above the grain (z-index: 1) and stays perfectly crisp: only the background is textured. Everything is tuned through CSS variables set on .fx-0256-root: size, background, corner radius, grain strength and pace. With --fgr-w: 100% and --fgr-h: 100% the surface fills its container, so a whole page header can be textured.

Measured in Chromium 151, Firefox 153 and WebKit 26.5: two copies on the same page each run on their own, nothing is added to window, no errors. The layer does not flash (constant average luminance, frame-by-frame measurement at 20 ms).

Accessibility

  • Reduced motion: under prefers-reduced-motion: reduce, the fgr-move animation is switched off. The grain stays visible, still: the texture is kept, only the shimmer goes.
  • Legibility: the grain lies under the content, never over it. At 15% it does not hinder reading; above 40% on a light background, check the contrast of your text.
  • Screen readers: the layer has aria-hidden="true". Only the text inside .fgr-content is read. If the surface stands for an image (record sleeve, photo), give it role="img" and an aria-label.
  • Keyboard and touch: nothing to activate, the effect is purely decorative. The layer has pointer-events: none: links and buttons placed in .fgr-content stay clickable.

Browser compatibility

CSS only: CSS variables, @keyframes with steps() and an feTurbulence SVG image as data:. Minimum versions from MDN data (CSS variables: Chrome 49, Firefox 31, Safari 9.1). Measured in Chromium 151, Firefox 153 and WebKit 26.5: same rendering and animation.

Chrome 49+✓ Full (measured)
Firefox 31+✓ Full (measured)
Safari 9.1+✓ Full (measured in WebKit)
Edge 79+✓ Full (Chromium engine)
Mobile iOS 9.3+✓ Full
Android Chrome 49+✓ Full

Without CSS variables the surface loses its size and background (browsers older than 2016). If the SVG image is not rendered, the surface stays plain with its content: nothing breaks.

The code

HTML structure to paste into your page (the CSS + JS come with your purchase):

index.html — structure
<div class="fx-0256-root">
  <div class="fgr-box">
    <div class="fgr-grain" aria-hidden="true"></div>
    <span class="fgr-content">…</span>
  </div>
</div>

One-time payment, no subscription — the code is yours forever

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
--fgr-w / --fgr-h 250px / 150px Size of the textured surface. 100% fills the container (the root then needs a height, see --fgr-root-h). The width never exceeds the root's.
--fgr-bg linear-gradient(135deg, #6366f1, #8b5cf6) Background under the grain: colour, gradient or photo (url(photo.jpg) center / cover).
--fgr-opacity .15 Grain strength. Around .3–.45 it shows clearly; at .05 it becomes a mere patina.
--fgr-speed .2s Duration of one 10-step loop. .4s gives a calmer grain; 1s a slow shimmer.
--fgr-radius 12px Corner radius of the surface; 0 for a section background.
--fgr-root-bg / --fgr-root-h #0a0a0f / 300px Background and minimum height of the root that centres the surface. transparent to lay the effect on your page, 0 so the root hugs the surface.
Content (HTML — .fgr-content) Text “GRAIN” Replace it with any content: heading, menu, button. It sits above the grain and stays crisp.

FAQ

Yes, a little: the SVG image has no size of its own, so the browser stretches it to the surface. On a 250 px area the grain is very fine; on a 1,400 px page header it gets coarser. For a fine grain over a very large area, add background-size: 300px to .fgr-grain (the pattern then repeats as tiles).
The fractalNoise filter produces noise on all four channels (red, green, blue, transparency). For a neutral grain, add filter: grayscale(1) to .fgr-grain.
No: a single transform animation per surface, which the browser hands to the graphics card. The noise image is computed once and then only moved. No JavaScript runs.