CSS Filter Generator

Build CSS filter effects with live sliders and presets — blur, brightness, saturation, hue rotation and drop shadow — and see the order-dependent result.

Drop your own image anywhere on this panel to preview the filter on it.

These are not 9 independent controls — 20 of 21 pairs depend on order

That filter order matters is easy to say and worth measuring, because the answer is more lopsided than it sounds. A CSS filter list applies left to right, each function taking the previous result as its input, so brightness(150%) contrast(150%) and contrast(150%) brightness(150%) are different instructions rather than two spellings of one. Take mid grey through both and you land on 0.875 one way and 0.75 the other. On rgb(102, 153, 51) the gap is 32 levels — the same two knobs, a visibly different green.

Inputbrightness then contrastcontrast then brightness
rgb(128, 128, 128) 223 191
rgb(102, 153, 51) rgb(166, 255, 51) rgb(134, 249, 19)

Sweeping every pair of the 7 colour filters over a 5,832-colour cube at three amounts each, 20 of the 21 pairs disagree somewhere. Only grayscale + invert gives the same answer whichever way round you write it. This page emits the functions in one fixed order — blur, brightness, contrast, saturate, hue-rotate, grayscale, sepia, invert, opacity — whatever you touched last, which is a reasonable choice and not one you can see from the sliders. It matters when you paste the CSS out and rearrange it by hand.

Most of that is the clamp, not the filters

Run the same sweep with the clamp to the displayable range switched off and the picture changes completely. CSS clamps each function's result to 0–1 before handing it on, so anything that pushes a channel past white or below black loses the overflow permanently — and the loss depends on when it happened.

BehaviourPairsof 21
Commute as pure arithmetic 12 57%
Still commute once clamped 1 5%
Broken only by the clamp to 0–1 11 52%
Genuinely non-commutative arithmetic 9 43%

Saturate and invert are the clean demonstration. They commute exactly while saturation stays at or below 100% and stop the moment it goes above: saturate(0) commutes, saturate(50%) commutes, saturate(100%) commutes, saturate(120%) does not, saturate(180%) does not, saturate(300%) does not. Nothing about the arithmetic changed at 120%. That is simply where saturate starts pushing channels out of range on some colours, and a clipped channel cannot be un-clipped by the next function in the list. The 9 genuinely non-commutative pairs — brightness with contrast, or anything with sepia — are a different matter, and no amount of headroom would fix those.

The invert slider's midpoint is a blank grey card

Drag invert to 50% and watch. The function computes a + v(1 − 2a) per channel, so what survives of the original picture is the factor (1 − 2a) — and at 50% that factor is zero. Running 140,608 colours through invert at each setting and counting how many distinct colours come out the other side gives one at the midpoint. Not nearly grey — every colour in the cube maps to exactly rgb(128, 128, 128).

InvertColours survivingShare of original
0% 140,608 1.00
25% 140,608 0.50
40% 140,608 0.20
45% 17,576 0.10
50% 1 0.00
75% 140,608 0.50
100% 140,608 1.00

Both ends of the slider keep the picture intact, and invert at a is the exact negative of invert at 1 − a. So this is not a fade from the original to its negative passing through something half-way. It is a fade out to flat grey and back in on the other side, and the middle is the one setting that destroys the image completely.

How to use

  1. Adjust the filter sliders.
  2. Reorder the filters to change the result.
  3. Try a preset as a starting point.
  4. Copy the generated CSS.

Frequently asked questions

Does the order of filters matter?

Very much. Filters apply in sequence, each acting on the output of the last, so blurring then brightening gives a different result from brightening then blurring. This surprises people expecting a set of independent adjustments.

How does drop-shadow differ from box-shadow?

The filter follows the actual visible shape including transparency, while box-shadow follows the element's rectangle. For a shadow that hugs the outline of a transparent image or a clipped shape, the filter is the only option.

Are filters expensive?

Blur particularly so, since it samples many surrounding pixels per pixel drawn. Applied to a large area or animated, it can cost real frame time on modest hardware. Colour adjustments like brightness and saturation are much cheaper.

Can I filter the background rather than the element?

Yes, with backdrop-filter, which applies to whatever sits behind the element rather than to the element itself. It is what produces frosted-glass panels, and it requires the element to be at least partly transparent for the effect to be visible.

Why has my filtered element started behaving strangely?

Because applying a filter creates a new containing block for fixed and absolutely positioned descendants, and a new stacking context. A fixed-position child inside a filtered ancestor positions relative to that ancestor instead of the viewport, which is a genuinely confusing bug to trace.

Can filters recolour an icon?

Indirectly and awkwardly. Turning a black icon into an arbitrary colour needs a chain of invert, sepia, saturate and hue-rotate values that is essentially found by trial. For anything other than a rough tint, an inline SVG with a fill colour is far more sensible.

🔒 This tool runs entirely in your browser. Nothing you enter is uploaded, logged, or stored.