Grainy Gradients
Gradients with a film-grain texture, in pure CSS. Set the grain once and every gradient below updates — then copy CSS that works anywhere, with no image files and no JavaScript.
Grainy gradient gallery
Every Copy CSS button includes the grainArcade Lime
Static Citron
Laser Aqua
Rave Kiwi
Afterglow Cobalt
Cyber Lagoon
Signal Ruby
Signal Mint
Rave Jade
Rave Ultraviolet
Synth Cobalt
Glow Emerald
Afterglow Fuchsia
Electric Acid
Laser Mint
Strobe Mint
Hyper Lemon
Plasma Mint
Cyber Ultraviolet
Plasma Cherry
Flux Lagoon
Pulse Lagoon
Signal Ember
Cyber Cyan
Grain works on all 600+ gradients in the library — open any gradient and switch on Grain under the preview, or build your own in the Gradient Generator.
How to make a grainy gradient in CSS
A grainy gradient is an ordinary CSS gradient with a layer of fine noise on top. The noise breaks up the smooth colour bands that gradients show on large screens, and gives flat UI a printed, tactile feel. You can do it with no image file at all: CSS can draw the noise itself with an inline SVG filter.
1. Make the noise with an SVG filter
SVG’s feTurbulence filter generates random noise. The rest of the filter turns it grey, makes it opaque, and boosts its contrast so it reads as grain rather than haze:
<svg xmlns='http://www.w3.org/2000/svg' width='220' height='220'> <filter id='g' color-interpolation-filters='sRGB'> <feTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='3' stitchTiles='stitch'/> <feColorMatrix type='saturate' values='0'/> <feComponentTransfer> <feFuncR type='linear' slope='2.5' intercept='-0.75'/> <feFuncG type='linear' slope='2.5' intercept='-0.75'/> <feFuncB type='linear' slope='2.5' intercept='-0.75'/> <feFuncA type='linear' slope='0' intercept='1'/> </feComponentTransfer> </filter> <rect width='100%' height='100%' filter='url(#g)' opacity='0.35'/> </svg>
baseFrequency sets the grain size: higher is finer (0.9), lower is coarser (0.4). The opacity on the rectangle sets how strong the grain is.
2. Put it on top of the gradient
URL-encode the SVG into a data: URI and list it before the gradient in background, so it sits on top. Then blend it with overlay:
.grainy {
background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='g' color-interpolation-filters='sRGB'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncR type='linear' slope='2.5' intercept='-0.75'/%3E%3CfeFuncG type='linear' slope='2.5' intercept='-0.75'/%3E%3CfeFuncB type='linear' slope='2.5' intercept='-0.75'/%3E%3CfeFuncA type='linear' slope='0' intercept='1'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23g)' opacity='0.35'/%3E%3C/svg%3E"),
linear-gradient(135deg, #FF6B6B, #845EC2);
background-blend-mode: overlay, normal;
}
overlay is what makes it look like grain rather than a grey film. The noise averages out at mid-grey, and mid-grey is neutral under overlay, so the gradient keeps its colours. Each speck only nudges the colour beneath it a little lighter or darker.
3. Tune it
- Strength: 20–40% suits most interfaces. Above 50% is a deliberate, risograph-style look.
- Size: fine grain for app backgrounds and cards, coarse grain for posters and hero sections.
- Dark gradients show grain less, so they usually need a little more.
- Text contrast: grain barely changes the average colour, so check contrast against the gradient itself.
Tailwind CSS
Tailwind has a utility for the blend mode, bg-blend-overlay. Add the noise and the gradient as one named background in your config, then use both classes together:
// tailwind.config.js
theme: {
extend: {
backgroundImage: {
'grainy-sunset': `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='g' color-interpolation-filters='sRGB'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncR type='linear' slope='2.5' intercept='-0.75'/%3E%3CfeFuncG type='linear' slope='2.5' intercept='-0.75'/%3E%3CfeFuncB type='linear' slope='2.5' intercept='-0.75'/%3E%3CfeFuncA type='linear' slope='0' intercept='1'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23g)' opacity='0.35'/%3E%3C/svg%3E"), linear-gradient(135deg, #FF6B6B, #845EC2)`,
},
},
},
<div class="bg-grainy-sunset bg-blend-overlay"></div>
Browser support and performance
background-blend-mode and SVG filters in data: URIs work in every current browser, including Safari, Chrome, Firefox and Edge. The browser draws the 220×220 noise tile once and repeats it, so it costs about the same as a small background image.
Frequently asked questions
What is a grainy gradient?
A colour gradient with a fine noise texture laid over it, like film grain or a risograph print. It is a popular look in current web and brand design because it softens gradients and stops them looking flat or digital.
Can I make a grainy gradient without an image?
Yes. Everything on this page is pure CSS: the noise is an SVG filter written inline as a data: URI, so there is no file to host and nothing to download.
Can I download a grainy gradient as an image?
Yes. Open any gradient, switch on Grain, and use the Download buttons to save a PNG at desktop, 4K, phone or square size with the grain included.
Why does my grain look grey or washed out?
The blend mode is missing or wrong. Without background-blend-mode: overlay, the noise sits on top as a semi-transparent grey layer instead of blending into the colours.
Is the CSS free to use?
Yes, in personal and commercial projects, with no attribution needed.
