Background Blur in CSS: backdrop-filter, blur() and When Each Makes Sense
backdrop-filter and filter: blur() do different things. Learn which CSS blur technique to reach for, when performance matters, and how to build glass effects right.
Two Different Blurs, Two Different Jobs
There are two ways to blur things in CSS and they're not interchangeable. filter: blur() blurs the element itself — its content, its children, the whole painted box. backdrop-filter: blur() blurs whatever is rendered *behind* the element, leaving the element's own content sharp. That distinction sounds small. It isn't.
If you're building a frosted-glass card sitting over a gradient, you want backdrop-filter. If you want a loading placeholder that's fuzzy, or a background image that's intentionally soft, you want filter: blur(). Reaching for the wrong one will either blur the text you wanted readable or leave the background entirely untouched — either way, your UI looks broken.
In practice, backdrop-filter is the one developers get confused about because it only works when there's actually something painted underneath the element in the stacking context. Transparent parent? White body? You'll get nothing. The blur needs content to work on, which is why glassmorphism components always pair a vivid gradient or image in the background with the frosted panel on top.
That said, both properties share the same underlying blur() function from the CSS Filter Effects spec, so the syntax is identical — blur(16px), blur(40px), whatever. The difference is purely what they target.
backdrop-filter: The Frosted Glass Property
Here's the minimal working glass card:
.glass-card {
background: rgba(255, 255, 255, 0.12);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px); /* Safari still needs this in 2026 */
border: 1px solid rgba(255, 255, 255, 0.25);
border-radius: 16px;
padding: 24px;
}That -webkit- prefix isn't optional if you care about Safari. Even in 2026, Safari desktop and iOS Safari require it. Drop it and your glass effect silently disappears for a significant chunk of your users. Worth noting: you can stack multiple filters — backdrop-filter: blur(20px) brightness(1.1) saturate(1.4) — and the combination often looks more convincing than blur alone.
The blur radius is more sensitive than most people expect. At 4px you barely see it. At 40px on a colourful gradient the background almost reads as a solid colour. Most production glassmorphism sits between 12px and 24px. The glassmorphism generator lets you scrub that value live so you can find the sweet spot for your specific background without guessing.
One more thing — backdrop-filter creates a new stacking context, just like transform or opacity does. That can affect z-index behaviour in ways that bite you if you're not expecting it. If a child element suddenly refuses to stack above something it should, that's usually the culprit.
filter: blur() — When You Want the Element Itself Blurred
The use cases for blurring the element itself are narrower but legit. Skeleton loading states where a placeholder image is intentionally blurred until the real one loads. A background hero image behind a header that you want soft without touching the HTML structure. Hover effects where something blurs when you don't focus it. Modals that blur the page content behind them — though for that you'd typically apply it to the page wrapper, not the modal.
/* Blur a hero image softly without touching its container */
.hero-image {
filter: blur(8px);
transform: scale(1.05); /* counteract the blur edge-fade */
}
/* Blur page content when modal is open */
.page-content.modal-open {
filter: blur(4px);
transition: filter 200ms ease;
}Quick aside: when you blur an element with filter, the edges of that element fade out — you get a soft halo effect at the boundary. That's why transform: scale(1.05) is the standard trick to crop the halo: scale up slightly so the blurry edges fall outside the visible area.
Honestly, the "blur the page when a modal opens" pattern is probably overused at this point. It looks slick the first time. By the fifth time you see it on a landing page it reads more like a template than a design decision. Use it when it genuinely adds context — not as a default modal style.
Performance: What You're Actually Paying
Both properties trigger compositing, which means the GPU is involved. That's generally fine on modern hardware. The problems show up at the edges: lots of blurred elements on a single page, animate them, do it on a mid-range Android device, and you'll see frame drops.
backdrop-filter is especially expensive because the browser has to sample the entire area *behind* the element every paint cycle. If that area is also animating — a scrolling background, a video, a canvas — you're compositing a moving target through every frame. On a 120Hz display that's 120 samples per second per blurred element.
The practical guidance: don't stack backdrop-filter on more than 3-4 elements simultaneously unless they're static. If you need many glass panels, consider faking the effect — a background: rgba() with no blur often reads as glass-ish when the rest of your design is doing the work. You lose the frosting, but you keep 60fps.
/* Performance fallback when backdrop-filter is too expensive */
@supports not (backdrop-filter: blur(1px)) {
.glass-card {
background: rgba(255, 255, 255, 0.3);
/* no blur, but still readable and vaguely glass-like */
}
}Look, will this affect a standard marketing page? Almost certainly not. But if you're building a data dashboard where 20 glass widgets are live-updating simultaneously, the performance budget matters. Profile before you commit. Chrome DevTools' Layers panel shows you exactly what's being composited and at what cost.
Will will-change Actually Help?
You'll see will-change: backdrop-filter recommended as a performance fix in a lot of older articles. The theory: hint to the browser to promote the element to its own GPU layer early, avoiding repaints. The reality in 2026 is more nuanced.
.glass-card {
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
will-change: backdrop-filter; /* hint: 'I intend to animate this' */
}Modern browsers are smart enough to promote composited-property elements automatically without the hint. will-change becomes valuable when you're *animating* the blur — say, transitioning from blur(0) to blur(20px) on hover — because it tells the browser to pre-allocate the layer before the animation starts. Without it, you can get a flash or jank on the first frame.
That said, will-change has a cost too. Every hinted element occupies GPU memory for the duration it's in the DOM. Slap it on dozens of elements and you'll actually make performance *worse*. Reserve it for elements where you've measured an actual jank problem, not as a blanket "make it faster" declaration.
Combining Both for Real-World Layouts
Real interfaces mix these two blur types more than people expect. A typical glassmorphism dashboard might have: a body background that's a blurred gradient image (using filter: blur() on a ::before pseudo-element), glass cards on top (using backdrop-filter), and modal overlays that blur the card content behind them (using filter: blur() on the card layer when a modal is active).
/* Blurred full-page gradient background */
body {
position: relative;
}
body::before {
content: '';
position: fixed;
inset: 0;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
filter: blur(60px);
transform: scale(1.1);
z-index: -1;
}
/* Glass card on top */
.card {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(16px);
-webkit-backdrop-filter: blur(16px);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 20px;
}The ::before trick is extremely useful. It decouples the blurred background from the document background, meaning you can animate the gradient colour or position without the blur re-calculating on every frame against live content. The background is independently blurred, static from the compositor's perspective, and the glass cards just float over it.
One more thing — if you want to explore what these combinations actually look like without writing code, the gradient generator and glassmorphism generator together let you prototype a full glass scene visually. It's a faster feedback loop than switching between your editor and browser for 12px vs 16px decisions.
Mixing styles across a design system also means you might pair glassmorphism panels with elements from other aesthetic directions — maybe a neobrutalism button living inside a glass card, or aurora-style gradients feeding your backdrop. CSS blur is just a property; how it reads depends entirely on what you put behind it.
Quick Reference: Which to Reach For
Here's the decision table you can actually bookmark:
Want to blur... Use
──────────────────────────────────────────────────────────
Everything BEHIND an element (frosted glass) backdrop-filter: blur()
The element's own content/children filter: blur()
A background image (hero, etc.) filter: blur() on image or ::before
Page content when modal opens filter: blur() on page wrapper
A placeholder/skeleton filter: blur() on the element
Multiple layered glass panels backdrop-filter, test perf carefullyIf you can only remember one rule: backdrop-filter = frosted glass over a background. filter = blur the thing itself. Every use case falls out of that.
For browser support, as of mid-2026: backdrop-filter is at 96.2% global coverage. The remaining gap is Firefox on Linux without hardware acceleration and a few niche WebView contexts. The @supports fallback pattern above covers you without any build tooling changes.
The spec for both lives in Filter Effects Module Level 1 and Filter Effects Level 2 (which introduced backdrop-filter). Worth reading if you want the actual mathematical definition of the Gaussian kernel — or if you just like knowing *why* blur(0) is valid and renders identically to blur(0px).
FAQ
The element behind your glass panel is probably solid white or has no content. backdrop-filter needs painted content underneath to blur — give the page a gradient or image background and it'll work immediately.
Yes, since Firefox 103 (2022). You don't need a prefix or flag anymore. The edge case is Firefox on Linux with hardware acceleration disabled, which you can handle with an @supports fallback.
backdrop-filter is generally heavier because it samples and composites everything behind the element on every frame. filter: blur() only processes the element itself. Both trigger GPU compositing, but stacking multiple backdrop-filter elements on animated content is where you'll actually see drops.
Yes, and it transitions smoothly. Use will-change: backdrop-filter on elements you plan to animate to avoid a jank spike on the first frame, but don't apply it globally — it eats GPU memory for every hinted element in the DOM.