Noise Texture Generator

Generate CSS noise textures as data URLs with live preview and copy-ready code. Customize grain and opacity. Free, no signup.

Preparing private browser tool…

Your file will stay on this device.

Why designers add noise to flat surfaces

A flat colour fill or a smooth gradient is mathematically perfect and, on many displays, visibly so. Large gradients in particular show banding, where the eight bits per channel available in a normal display cannot represent the gradual change and the transition breaks into visible stripes. Adding a small amount of random per-pixel variation breaks the boundaries between those bands, so the eye reads a continuous ramp instead of steps. The same technique in print and audio is called dithering.

Beyond fixing banding, noise adds material character. A faint grain over a dark card reads as paper, film or fabric rather than as a rectangle of hex colour, which is why it appears so often in editorial layouts and in dark interfaces where flat panels can feel plasticky.

The amount needed is much smaller than most people expect. Somewhere between three and ten percent opacity over a large surface is usually enough to remove banding and add texture without the grain itself becoming a visible pattern.

How this generator builds the texture

The tool creates an offscreen canvas at the chosen size and fills an ImageData buffer one pixel at a time. For each pixel it draws a random number: if the number falls outside the density threshold the pixel is written as fully transparent, and if it falls inside, the pixel gets a colour and the alpha value derived from the opacity slider.

The monochrome option decides what that colour is. When it is on, one random value between 0 and 255 is written to all three channels, producing a grey speck. When it is off, each of the red, green and blue channels gets its own random value, producing coloured speckle that reads as chroma noise rather than film grain. Monochrome is the right default for almost every interface use.

The canvas is then exported with toDataURL as a PNG and wrapped in a CSS declaration, so the output is a line of the form background-image: url("data:image/png;base64,iVBORw0KGgo..."). Every pixel is independent white noise: there is no Perlin or simplex structure here, so the result has no clouds, no swirls and no scale, which is exactly what you want for grain.

Density, opacity and tile size in practice

Density is the proportion of pixels that receive any colour at all. At 100 percent every pixel is noise and the texture is dense static. At 20 percent only a fifth of the pixels are painted and the rest stay transparent, which produces sparse specks with the underlying colour showing through. Density controls how busy the grain looks; opacity controls how strongly it competes with what is behind it.

Tile size matters more than it first appears. The generated image is repeated across the surface by the browser's default background-repeat, so a small tile repeats often enough that the eye can pick out the recurring pattern, particularly on a large hero. A 64 pixel tile tiles visibly; 200 to 512 pixels is usually large enough that the repeat is not detectable. The cost is file size, since a noise PNG compresses poorly by nature and a large one can run to a few hundred kilobytes as a data URL.

Because random data is close to incompressible, PNG compression achieves very little here. If the data URL is larger than you want in your stylesheet, drop the tile size, lower the density so more pixels are transparent and compress better, or save the PNG as a separate file and reference it by URL so it can be cached independently of the CSS.

Applying the texture without hurting readability

The generated declaration can go straight onto an element, but layering it over an existing background is usually better. CSS allows multiple backgrounds, so background-image: url("data:image/png;base64,..."), linear-gradient(#1a1a2e, #0a0a14) puts the noise on top of the gradient in a single element with no extra markup.

For finer control, put the noise on a pseudo-element: give the container position: relative, then style ::after with content: "", position: absolute, inset: 0, the noise background, a low opacity, and pointer-events: none so it never intercepts clicks. That structure lets you fade the grain in and out, or disable it inside a media query, without touching the element's own background.

Two accessibility points are worth respecting. Keep the noise underneath text rather than over it, because grain reduces effective contrast and can push a passing colour pair below the WCAG threshold. And because a static grain is not motion, it is unaffected by prefers-reduced-motion; what you should honour instead is a design that still reads correctly if the texture fails to load.

Frequently asked questions

Why is the data URL so large?
Random pixel data has almost no redundancy, so PNG compression barely reduces it. Size grows with the square of the tile dimension and with density, since transparent pixels compress far better than coloured ones. Reduce the tile size, lower the density, or save the image as a separate cached file instead of inlining it.
What opacity should I use?
For interface work, roughly three to ten percent over a large surface. Above about fifteen percent the grain stops reading as texture and starts reading as an effect, and it begins to eat into text contrast. Start low and raise it only until banding disappears.
Why can I see the tile repeating?
The image is tiled by the browser, so a small tile repeats often enough for the eye to lock onto the pattern. Increase the tile size to 256 pixels or more, which pushes the repeat interval past the point where it is noticeable on a typical hero section.
Is this Perlin noise?
No. Every pixel is drawn independently, which is white noise with no spatial structure. Perlin and simplex noise produce smooth, correlated fields useful for clouds, terrain and marble. For film grain and for dithering a gradient, uncorrelated white noise is what you want.
Should I use monochrome or colour noise?
Monochrome for nearly all interface work, since grey speckle reads as grain and does not shift the hue of the surface underneath. Colour noise writes a separate random value to each channel, which produces visible chroma speckle that suits a deliberately glitchy or analogue look.
Can I use an SVG filter instead?
Yes. An SVG feTurbulence filter generates noise procedurally, so the markup stays tiny and the result scales without tiling. The tradeoff is that the filter is recomputed by the browser rather than decoded once, which can cost more at paint time on large surfaces and on low-powered devices.