[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"verticals":3,"quiz-css-backdrop-filter-frosted-glass":44,"search-suggestions":60,"quiz-article-css-backdrop-filter-frosted-glass":109},[4,20,32],{"id":5,"slug":6,"name":7,"tagline":8,"description":9,"accentFrom":10,"accentTo":11,"icon":12,"defaultLocale":13,"locales":14,"features":16,"position":19},"019fe637-3d33-714b-b57f-23e163ffca0c","dev","Web Development","Read it. Run it. Prove it.","A post a day on modern web development — most with an editable playground and a quiz that explains every answer. Free, no account needed.","violet-500","cyan-400","◇","en",[13,15],"fa",{"courses":17,"paths":17,"articles":17,"exams":18,"flashcards":18,"packages":17,"community":17,"certificates":17,"teams":17,"commerce":17},true,false,0,{"id":21,"slug":22,"name":23,"tagline":24,"description":25,"accentFrom":26,"accentTo":10,"icon":27,"defaultLocale":13,"locales":28,"features":30,"position":31},"019fe637-3dc2-754c-8657-0f175bfee7c6","lang","Languages","Learn a language the way you learn a codebase.","Grammar explained the way good documentation explains an API — one idea at a time, each with a quiz.","amber-400","⌘",[13,15,29],"es",{"courses":18,"paths":18,"articles":17,"exams":18,"flashcards":17,"packages":18,"community":17,"certificates":17,"teams":18,"commerce":18},2,{"id":33,"slug":34,"name":35,"tagline":36,"description":37,"accentFrom":38,"accentTo":39,"icon":40,"defaultLocale":13,"locales":41,"features":42,"position":43},"7b3c16f2-931d-410e-802e-e1fa4edab7de","soft","Soft Skills","The half of the job nobody wrote documentation for.","Weekly, on the parts of working life that decide more than your code does — first weeks, meetings, interviews, promotions, and the people around you. Written from what actually happens, and recorded as a podcast you can listen to on the walk.","emerald-400","teal-300","◉",[13],{"courses":18,"paths":18,"articles":17,"exams":18,"flashcards":18,"packages":18,"community":17,"certificates":18,"teams":18,"commerce":18},3,{"id":45,"slug":46,"kind":47,"title":48,"description":49,"config":50,"verticalId":5,"vertical":55,"course":52,"_count":56,"access":57,"attempts":59,"questionCount":51},"01a0ec73-03d7-77d9-9661-a653a7f4e21c","css-backdrop-filter-frosted-glass","PRACTICE_QUIZ","backdrop-filter: frosted glass, stacking contexts, and cost","Check what actually stuck: the transparency rule that makes or breaks the frosted-glass effect, the stacking context backdrop-filter quietly opens, and when the blur becomes a performance problem.",{"questionCount":51,"timeLimitSec":52,"shuffleQuestions":18,"shuffleOptions":17,"negativeMarking":19,"passScorePct":53,"maxAttempts":52,"revealAnswers":54,"allowFlagging":18,"allowBacktracking":17},9,null,70,"AFTER_SUBMIT",{"slug":6,"name":7},{"questions":51},{"allowed":17,"reason":58},"FREE",[],[61,65,69,73,77,81,85,89,93,97,101,105],{"slug":62,"name":63,"articles":64},"webdev","Webdev",117,{"slug":66,"name":67,"articles":68},"javascript","Javascript",98,{"slug":70,"name":71,"articles":72},"frontend","Frontend",76,{"slug":74,"name":75,"articles":76},"tutorial","Tutorial",43,{"slug":78,"name":79,"articles":80},"css","Css",37,{"slug":82,"name":83,"articles":84},"typescript","Typescript",17,{"slug":86,"name":87,"articles":88},"performance","Performance",14,{"slug":90,"name":91,"articles":92},"react","React",13,{"slug":94,"name":95,"articles":96},"browser","Browser",11,{"slug":98,"name":99,"articles":100},"node","Node",10,{"slug":102,"name":103,"articles":104},"html","Html",8,{"slug":106,"name":107,"articles":108},"accessibility","Accessibility",7,{"id":110,"slug":46,"title":111,"subtitle":52,"excerpt":112,"coverUrl":113,"locale":13,"readingMinutes":108,"publishedAt":114,"viewCount":115,"likeCount":19,"commentCount":19,"author":116,"vertical":121,"topic":122,"tags":124,"_count":129,"playground":131,"body":133,"bodyMd":278,"seo":279,"translationGroupId":282,"series":52,"podcastUrl":52,"verticalId":5,"thread":283,"assessments":285,"translations":288,"quiz":290},"01a0ec73-013a-70ca-bcf4-046f64b93003","Your `backdrop-filter` Is Working. Your Background Is Hiding It.","backdrop-filter looks like a one-line copy from a Codepen: blur(20px), ship the frosted navbar. Half the time it renders as a plain flat panel instead — because backdrop-filter blurs whatever is BEHIND an element, and that only shows up if the element itself is see-through. Here's the transparency rule, the stacking-context trap it quietly sets, and why it's one of the priciest effects you can scroll past.","\u002Fmedia\u002Fcovers\u002Fcss-backdrop-filter-frosted-glass.png","2026-09-30T12:10:22.069Z",44,{"id":117,"name":118,"username":119,"avatarUrl":52,"headline":120},"019fe637-3c25-7088-9034-39c9f15dc3c8","Parsa Jiravand","parsa","Frontend engineer · building bestpractic",{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":78,"name":123},"CSS",[125,126,127,128],{"slug":78,"name":79,"color":52},{"slug":62,"name":63,"color":52},{"slug":70,"name":71,"color":52},{"slug":74,"name":75,"color":52},{"assessments":130},1,{"slug":46,"title":132},"backdrop-filter — interactive playground",{"blocks":134,"version":130},[135,139,144,147,150,154,157,160,163,166,169,172,175,178,181,184,188,191,194,200,203,206,209,212,215,218,221,224,227,230,233,236,239,242,245,248,251,254,260,263,266,269,272],{"id":136,"html":137,"type":138},"b1","\u003Cp>You find a frosted navbar on Dribbble, the kind that sits over a hero image with the content underneath swimming softly out of focus behind it — Apple&#39;s Control Center look, everywhere in 2026 UI. You copy the one line that&#39;s supposed to do it:\u003C\u002Fp>","paragraph",{"id":140,"code":141,"type":142,"language":78,"highlight":143},"b2",".navbar {\n  background: white;\n  backdrop-filter: blur(20px);\n}","code",[],{"id":145,"html":146,"type":138},"b3","\u003Cp>Ship it. Refresh. The navbar is just... a white bar. No blur, no glass, nothing swimming behind it. You bump the blur to \u003Ccode>40px\u003C\u002Fcode>, then \u003Ccode>80px\u003C\u002Fcode>, convinced you fat-fingered a unit. Still nothing. You open dev tools, and the property is right there, applied, not crossed out, not overridden. It&#39;s just doing nothing you can see.\u003C\u002Fp>",{"id":148,"html":149,"type":138},"b4","\u003Cp>It isn&#39;t broken. It&#39;s doing exactly what you told it to do — you just told it to blur something you&#39;d already hidden.\u003C\u002Fp>",{"id":151,"html":152,"text":152,"type":153,"level":31},"b5","The wrong way, and why it feels right","heading",{"id":155,"html":156,"type":138},"b6","\u003Cp>\u003Ccode>background: white\u003C\u002Fcode> and \u003Ccode>backdrop-filter: blur(20px)\u003C\u002Fcode> on the same element feels like two independent style declarations: one sets a color, one adds an effect. That&#39;s how almost every other CSS property behaves — \u003Ccode>border-radius\u003C\u002Fcode> doesn&#39;t care what \u003Ccode>background\u003C\u002Fcode> says, \u003Ccode>box-shadow\u003C\u002Fcode> doesn&#39;t either. So it&#39;s reasonable to assume you can mix and match freely.\u003C\u002Fp>",{"id":158,"html":159,"type":138},"b7","\u003Cp>\u003Ccode>backdrop-filter\u003C\u002Fcode> isn&#39;t independent, because of what &quot;backdrop&quot; means. It doesn&#39;t touch the element or its content the way \u003Ccode>filter: blur(20px)\u003C\u002Fcode> would — \u003Ccode>filter\u003C\u002Fcode> blurs the element and everything inside it, into a mushy blob. \u003Ccode>backdrop-filter\u003C\u002Fcode> reaches \u003Cem>behind\u003C\u002Fem> the element, samples whatever&#39;s already rendered back there — the hero image, the page content scrolling underneath — blurs that, and paints it in as the element&#39;s background layer.\u003C\u002Fp>",{"id":161,"html":162,"type":138},"b8","\u003Cp>Which means: if the element&#39;s actual \u003Ccode>background\u003C\u002Fcode> is a fully opaque \u003Ccode>white\u003C\u002Fcode>, that opaque white paints on top of the blurred result, covering it completely. You&#39;re not seeing &quot;no blur.&quot; You&#39;re seeing full-opacity white sitting on top of a blur that&#39;s happening perfectly correctly, one paint layer down, where you can never see it.\u003C\u002Fp>",{"id":164,"html":165,"type":138},"b9","\u003C!-- playground:start -->",{"id":167,"html":168,"text":168,"type":153,"level":31},"b10","🎮 Try it yourself",{"id":170,"html":171,"type":138},"b11","\u003Cp>\u003Cstrong>\u003Ca href=\"https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fcss-backdrop-filter-frosted-glass\u002Fplayground\">▶️ Open the interactive playground →\u003C\u002Fa>\u003C\u002Fstrong>\u003C\u002Fp>",{"id":173,"html":174,"type":138},"b12","\u003Cp>\u003Cem>Runs right in your browser — poke at it and watch the concept react live.\u003C\u002Fem>\u003C\u002Fp>",{"id":176,"html":177,"type":138},"b13","\u003C!-- playground:end -->",{"id":179,"html":180,"text":180,"type":153,"level":31},"b14","The one property that fixes it",{"id":182,"html":183,"type":138},"b15","\u003Cp>The fix isn&#39;t more blur. It&#39;s less opacity:\u003C\u002Fp>",{"id":185,"code":186,"type":142,"language":78,"highlight":187},"b16",".navbar {\n  background: rgba(255, 255, 255, 0.55);\n  backdrop-filter: blur(20px);\n}",[],{"id":189,"html":190,"type":138},"b17","\u003Cp>That \u003Ccode>0.55\u003C\u002Fcode> alpha is the entire trick. Now there&#39;s a translucent white tint sitting \u003Cem>on top of\u003C\u002Fem> the blurred backdrop instead of a solid one hiding it — which is exactly the &quot;frosted glass&quot; look: not &quot;blur,&quot; but &quot;blur, plus a faint wash of color over it.&quot; Apple&#39;s classic blur materials work the same way: a blur, then a semi-transparent tint layered on. Drop the alpha closer to \u003Ccode>0\u003C\u002Fcode> and you get more of the scene showing through, softer glass; push it toward \u003Ccode>1\u003C\u002Fcode> and you&#39;re back to the flat panel you started with, just with a blur nobody can see.\u003C\u002Fp>",{"id":192,"html":193,"type":138},"b18","\u003Cp>Two API details worth knowing before you rely on this:\u003C\u002Fp>",{"id":195,"type":196,"items":197,"ordered":18},"b19","list",[198,199],"\u003Cstrong>\u003Ccode>backdrop-filter\u003C\u002Fcode> takes the same filter functions as \u003Ccode>filter\u003C\u002Fcode>\u003C\u002Fstrong> — \u003Ccode>blur()\u003C\u002Fcode>, \u003Ccode>brightness()\u003C\u002Fcode>, \u003Ccode>contrast()\u003C\u002Fcode>, \u003Ccode>saturate()\u003C\u002Fcode>, \u003Ccode>grayscale()\u003C\u002Fcode>, and you can stack several space-separated. The frosted-glass look usually isn&#39;t just \u003Ccode>blur()\u003C\u002Fcode> — pairing it with \u003Ccode>saturate(180%)\u003C\u002Fcode> is what gives it that slightly punchy, &quot;more colorful than reality&quot; look Control Center has, because a plain blur alone tends to look washed-out and grey.","\u003Cstrong>It needs no vendor prefix on any current browser.\u003C\u002Fstrong> Safari required \u003Ccode>-webkit-backdrop-filter\u003C\u002Fcode> for years and plenty of tutorials still paste both; today&#39;s Safari, Chrome, Firefox and Edge all ship the unprefixed property, so the prefix is legacy insurance, not a requirement — but &quot;years&quot; only ended with Safari 18 in September 2024, so \u003Ccode>backdrop-filter\u003C\u002Fcode> is Baseline 2024 (newly available), not yet widely available. If your targets include iOS\u002FSafari 17 or older, keep \u003Ccode>-webkit-backdrop-filter\u003C\u002Fcode> next to the unprefixed line (\u003Ca href=\"https:\u002F\u002Fcaniuse.com\u002Fcss-backdrop-filter\">caniuse\u003C\u002Fa>).",{"id":201,"html":202,"text":202,"type":153,"level":31},"b20","The bug that shows up one sprint later: it makes its own stacking context",{"id":204,"html":205,"type":138},"b21","\u003Cp>Say the frosted navbar works now — glass, tint, all correct. Then someone adds a dropdown menu inside it, positioned absolutely, \u003Ccode>z-index: 999\u003C\u002Fcode> because nothing was ever going to out-rank it. And it renders \u003Cem>underneath\u003C\u002Fem> a modal that opens later in the page, a modal whose own \u003Ccode>z-index\u003C\u002Fcode> is a modest \u003Ccode>10\u003C\u002Fcode>.\u003C\u002Fp>",{"id":207,"html":208,"type":138},"b22","\u003Cp>\u003Ccode>999 &gt; 10\u003C\u002Fcode>. That should never lose. Except \u003Ccode>backdrop-filter\u003C\u002Fcode> — the moment its value isn&#39;t \u003Ccode>none\u003C\u002Fcode> — forces the element onto its own new \u003Cstrong>stacking context\u003C\u002Fstrong>, the same rule that \u003Ccode>opacity\u003C\u002Fcode> below \u003Ccode>1\u003C\u002Fcode>, \u003Ccode>transform\u003C\u002Fcode>, and \u003Ccode>will-change\u003C\u002Fcode> already follow. A \u003Ccode>z-index\u003C\u002Fcode> only ever competes against siblings \u003Cem>inside the stacking context it was declared in\u003C\u002Fem>. Once the navbar becomes its own context, \u003Ccode>999\u003C\u002Fcode> stops meaning &quot;above almost everything on the page&quot; and starts meaning &quot;above everything else inside this one blurred box&quot; — a much smaller, much more local promise than it looks like.\u003C\u002Fp>",{"id":210,"html":211,"type":138},"b23","\u003Cp>This is exactly the same trap \u003Ccode>transform\u003C\u002Fcode> and \u003Ccode>opacity\u003C\u002Fcode> have quietly set for a decade; \u003Ccode>backdrop-filter\u003C\u002Fcode> just added itself to the guest list without most people noticing, because nobody reads the stacking-context spec before reaching for a glass effect. The fix is the same one you&#39;d use for any stacking-context surprise: stop comparing \u003Ccode>z-index\u003C\u002Fcode> numbers across the boundary and instead move the dropdown out of the blurred container (render it in a portal, or as a sibling instead of a child), so it stacks against the page&#39;s actual top-level contexts instead of getting trapped inside the navbar&#39;s private one. It also becomes the containing block for \u003Ccode>position: fixed\u003C\u002Fcode> descendants, so a &quot;full-screen&quot; menu rendered inside the blurred navbar gets sized to the navbar, not the viewport — the same portal fix solves both. (If your navbar is already \u003Ccode>position: sticky\u003C\u002Fcode> or \u003Ccode>fixed\u003C\u002Fcode>, it was a stacking context before the blur — same trap, same fix.)\u003C\u002Fp>",{"id":213,"html":214,"text":214,"type":153,"level":31},"b24","The cost nobody notices until the scroll feels wrong",{"id":216,"html":217,"type":138},"b25","\u003Cp>Here&#39;s the part that doesn&#39;t show up in a screenshot: \u003Ccode>backdrop-filter\u003C\u002Fcode> is one of the most expensive things you can ask a browser to paint, and it pays that cost \u003Cstrong>again on every frame where anything behind the blurred region changes\u003C\u002Fstrong> — not once, at first paint. A blur isn&#39;t a filed-away static image; it&#39;s a real-time recomputation of &quot;take everything currently behind this box and re-blur it,&quot; and if the page scrolls, or the content behind the glass panel is animating, that recomputation has to happen again on the next frame, and the one after that, for as long as the backdrop keeps changing.\u003C\u002Fp>",{"id":219,"html":220,"type":138},"b26","\u003Cp>A small blurred badge over a static hero image barely registers. A full-viewport blurred overlay sitting on top of a long, actively scrolling page is a different animal — the browser is re-blurring a screen-sized region on every scroll tick, on whatever GPU the visitor&#39;s phone happens to have, and low-to-mid-range mobile hardware is where that bill comes due first: scrolling that feels a half-step behind your finger instead of stuck to it. There&#39;s no universal number to quote here — it depends on the blurred area&#39;s size, the blur radius, and the device — which is exactly why you test it on the actual hardware your users carry, not just the laptop it was built on.\u003C\u002Fp>",{"id":222,"html":223,"type":138},"b27","\u003Cp>The practical rule: keep the blurred surface \u003Cstrong>small and mostly static\u003C\u002Fstrong> — a nav bar, a fixed card, a modal backdrop that isn&#39;t itself scrolling — and be skeptical of any design that blurs a large area the user is actively scrolling behind. If a design calls for that anyway, that&#39;s the moment to profile it on a mid-range Android before you ship, not after support tickets say &quot;the new nav feels laggy.&quot;\u003C\u002Fp>",{"id":225,"html":226,"type":138},"b28","\u003C!-- quiz:start -->",{"id":228,"html":229,"text":229,"type":153,"level":31},"b29","🧠 Test yourself",{"id":231,"html":232,"type":138},"b30","\u003Cp>Think it clicked? \u003Cstrong>\u003Ca href=\"https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fcss-backdrop-filter-frosted-glass\u002Fquiz\">Take the 9-question quiz →\u003C\u002Fa>\u003C\u002Fstrong>\u003C\u002Fp>",{"id":234,"html":235,"type":138},"b31","\u003Cp>\u003Cem>Instant feedback, a hint on every question, and an explanation for each answer — right or wrong.\u003C\u002Fem>\u003C\u002Fp>",{"id":237,"html":238,"type":138},"b32","\u003C!-- quiz:end -->",{"id":240,"html":241,"text":241,"type":153,"level":31},"b33","The takeaway",{"id":243,"html":244,"type":138},"b34","\u003Cp>\u003Ccode>backdrop-filter\u003C\u002Fcode> isn&#39;t a broken \u003Ccode>filter\u003C\u002Fcode> — it&#39;s a different property with a different subject. \u003Ccode>filter\u003C\u002Fcode> blurs the element; \u003Ccode>backdrop-filter\u003C\u002Fcode> blurs whatever&#39;s \u003Cem>behind\u003C\u002Fem> it, which only becomes visible once the element itself stops hiding that blur behind an opaque background. Get the transparency right and you&#39;ve got the effect. Forget that it also opens a new stacking context, and a \u003Ccode>z-index\u003C\u002Fcode> you were sure would win quietly loses to a scope you didn&#39;t know existed. And treat the blur radius as a performance budget, not a free design knob — the frame it costs shows up on someone&#39;s phone, not in your editor.\u003C\u002Fp>",{"id":246,"html":247,"type":138},"b35","\u003Cp>Have you shipped a frosted panel that turned out to be a flat one for a sprint before anyone noticed? What gave it away — the missing blur, or the z-index fight?\u003C\u002Fp>",{"id":249,"html":250,"type":138},"b36","\u003C!-- related:start -->",{"id":252,"html":253,"text":253,"type":153,"level":31},"b37","📚 Read next",{"id":255,"type":196,"items":256,"ordered":18},"b38",[257,258,259],"\u003Ca href=\"https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fcss-color-scheme-native-dark-mode-form-controls\">The CSS Property That Fixes Dark Mode&#39;s Ugly White Boxes\u003C\u002Fa>","\u003Ca href=\"https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fcss-accent-color-native-form-control-tinting\">One CSS Property Replaces Your Checkbox Hack\u003C\u002Fa>","\u003Ca href=\"https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fcss-color-mix-native-color-mixing\">You reach for Sass to mix colors. \u003Ccode>color-mix()\u003C\u002Fcode> does it natively.\u003C\u002Fa>",{"id":261,"html":262,"type":138},"b39","\u003C!-- related:end -->",{"id":264,"type":265},"b40","divider",{"id":267,"html":268,"type":138},"b41","\u003Cp>🚀 \u003Cstrong>Want more like this?\u003C\u002Fstrong> Every guide, playground, and quiz lives on \u003Cstrong>\u003Ca href=\"https:\u002F\u002Fbestpractic.org\u002F\">bestpractic.org\u003C\u002Fa>\u003C\u002Fstrong> — open it and \u003Cstrong>\u003Ca href=\"https:\u002F\u002Fbestpractic.org\u002F\">sign up free\u003C\u002Fa>\u003C\u002Fstrong> so the next one finds you.\u003C\u002Fp>",{"id":270,"html":271,"type":138},"b42","\u003Cp>\u003Cem>Thanks for reading! Let&#39;s stay connected:\u003C\u002Fem>\u003C\u002Fp>",{"id":273,"type":196,"items":274,"ordered":18},"b43",[275,276,277],"⭐ \u003Cstrong>GitHub\u003C\u002Fstrong> — follow me and star the projects: \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fparsajiravand\">github.com\u002Fparsajiravand\u003C\u002Fa>","💬 \u003Cstrong>Discord\u003C\u002Fstrong> — join the frontend best-practices community: \u003Ca href=\"https:\u002F\u002Fdiscord.gg\u002Fd9KRhuAwQ\">discord.gg\u002Fd9KRhuAwQ\u003C\u002Fa>","📸 \u003Cstrong>Instagram\u003C\u002Fstrong> — frontend best practices, daily: \u003Ca href=\"https:\u002F\u002Fwww.instagram.com\u002Fbestpractice___\u002F\">@bestpractice___\u003C\u002Fa>","You find a frosted navbar on Dribbble, the kind that sits over a hero image with the content underneath swimming softly out of focus behind it — Apple's Control Center look, everywhere in 2026 UI. You copy the one line that's supposed to do it:\n\n```css\n.navbar {\n  background: white;\n  backdrop-filter: blur(20px);\n}\n```\n\nShip it. Refresh. The navbar is just... a white bar. No blur, no glass, nothing swimming behind it. You bump the blur to `40px`, then `80px`, convinced you fat-fingered a unit. Still nothing. You open dev tools, and the property is right there, applied, not crossed out, not overridden. It's just doing nothing you can see.\n\nIt isn't broken. It's doing exactly what you told it to do — you just told it to blur something you'd already hidden.\n\n## The wrong way, and why it feels right\n\n`background: white` and `backdrop-filter: blur(20px)` on the same element feels like two independent style declarations: one sets a color, one adds an effect. That's how almost every other CSS property behaves — `border-radius` doesn't care what `background` says, `box-shadow` doesn't either. So it's reasonable to assume you can mix and match freely.\n\n`backdrop-filter` isn't independent, because of what \"backdrop\" means. It doesn't touch the element or its content the way `filter: blur(20px)` would — `filter` blurs the element and everything inside it, into a mushy blob. `backdrop-filter` reaches *behind* the element, samples whatever's already rendered back there — the hero image, the page content scrolling underneath — blurs that, and paints it in as the element's background layer.\n\nWhich means: if the element's actual `background` is a fully opaque `white`, that opaque white paints on top of the blurred result, covering it completely. You're not seeing \"no blur.\" You're seeing full-opacity white sitting on top of a blur that's happening perfectly correctly, one paint layer down, where you can never see it.\n\n\u003C!-- playground:start -->\n\n## 🎮 Try it yourself\n\n**[▶️ Open the interactive playground →](https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fcss-backdrop-filter-frosted-glass\u002Fplayground)**\n\n_Runs right in your browser — poke at it and watch the concept react live._\n\n\u003C!-- playground:end -->\n\n## The one property that fixes it\n\nThe fix isn't more blur. It's less opacity:\n\n```css\n.navbar {\n  background: rgba(255, 255, 255, 0.55);\n  backdrop-filter: blur(20px);\n}\n```\n\nThat `0.55` alpha is the entire trick. Now there's a translucent white tint sitting *on top of* the blurred backdrop instead of a solid one hiding it — which is exactly the \"frosted glass\" look: not \"blur,\" but \"blur, plus a faint wash of color over it.\" Apple's classic blur materials work the same way: a blur, then a semi-transparent tint layered on. Drop the alpha closer to `0` and you get more of the scene showing through, softer glass; push it toward `1` and you're back to the flat panel you started with, just with a blur nobody can see.\n\nTwo API details worth knowing before you rely on this:\n\n- **`backdrop-filter` takes the same filter functions as `filter`** — `blur()`, `brightness()`, `contrast()`, `saturate()`, `grayscale()`, and you can stack several space-separated. The frosted-glass look usually isn't just `blur()` — pairing it with `saturate(180%)` is what gives it that slightly punchy, \"more colorful than reality\" look Control Center has, because a plain blur alone tends to look washed-out and grey.\n- **It needs no vendor prefix on any current browser.** Safari required `-webkit-backdrop-filter` for years and plenty of tutorials still paste both; today's Safari, Chrome, Firefox and Edge all ship the unprefixed property, so the prefix is legacy insurance, not a requirement — but \"years\" only ended with Safari 18 in September 2024, so `backdrop-filter` is Baseline 2024 (newly available), not yet widely available. If your targets include iOS\u002FSafari 17 or older, keep `-webkit-backdrop-filter` next to the unprefixed line ([caniuse](https:\u002F\u002Fcaniuse.com\u002Fcss-backdrop-filter)).\n\n## The bug that shows up one sprint later: it makes its own stacking context\n\nSay the frosted navbar works now — glass, tint, all correct. Then someone adds a dropdown menu inside it, positioned absolutely, `z-index: 999` because nothing was ever going to out-rank it. And it renders *underneath* a modal that opens later in the page, a modal whose own `z-index` is a modest `10`.\n\n`999 > 10`. That should never lose. Except `backdrop-filter` — the moment its value isn't `none` — forces the element onto its own new **stacking context**, the same rule that `opacity` below `1`, `transform`, and `will-change` already follow. A `z-index` only ever competes against siblings *inside the stacking context it was declared in*. Once the navbar becomes its own context, `999` stops meaning \"above almost everything on the page\" and starts meaning \"above everything else inside this one blurred box\" — a much smaller, much more local promise than it looks like.\n\nThis is exactly the same trap `transform` and `opacity` have quietly set for a decade; `backdrop-filter` just added itself to the guest list without most people noticing, because nobody reads the stacking-context spec before reaching for a glass effect. The fix is the same one you'd use for any stacking-context surprise: stop comparing `z-index` numbers across the boundary and instead move the dropdown out of the blurred container (render it in a portal, or as a sibling instead of a child), so it stacks against the page's actual top-level contexts instead of getting trapped inside the navbar's private one. It also becomes the containing block for `position: fixed` descendants, so a \"full-screen\" menu rendered inside the blurred navbar gets sized to the navbar, not the viewport — the same portal fix solves both. (If your navbar is already `position: sticky` or `fixed`, it was a stacking context before the blur — same trap, same fix.)\n\n## The cost nobody notices until the scroll feels wrong\n\nHere's the part that doesn't show up in a screenshot: `backdrop-filter` is one of the most expensive things you can ask a browser to paint, and it pays that cost **again on every frame where anything behind the blurred region changes** — not once, at first paint. A blur isn't a filed-away static image; it's a real-time recomputation of \"take everything currently behind this box and re-blur it,\" and if the page scrolls, or the content behind the glass panel is animating, that recomputation has to happen again on the next frame, and the one after that, for as long as the backdrop keeps changing.\n\nA small blurred badge over a static hero image barely registers. A full-viewport blurred overlay sitting on top of a long, actively scrolling page is a different animal — the browser is re-blurring a screen-sized region on every scroll tick, on whatever GPU the visitor's phone happens to have, and low-to-mid-range mobile hardware is where that bill comes due first: scrolling that feels a half-step behind your finger instead of stuck to it. There's no universal number to quote here — it depends on the blurred area's size, the blur radius, and the device — which is exactly why you test it on the actual hardware your users carry, not just the laptop it was built on.\n\nThe practical rule: keep the blurred surface **small and mostly static** — a nav bar, a fixed card, a modal backdrop that isn't itself scrolling — and be skeptical of any design that blurs a large area the user is actively scrolling behind. If a design calls for that anyway, that's the moment to profile it on a mid-range Android before you ship, not after support tickets say \"the new nav feels laggy.\"\n\n\u003C!-- quiz:start -->\n\n## 🧠 Test yourself\n\nThink it clicked? **[Take the 9-question quiz →](https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fcss-backdrop-filter-frosted-glass\u002Fquiz)**\n\n_Instant feedback, a hint on every question, and an explanation for each answer — right or wrong._\n\n\u003C!-- quiz:end -->\n\n## The takeaway\n\n`backdrop-filter` isn't a broken `filter` — it's a different property with a different subject. `filter` blurs the element; `backdrop-filter` blurs whatever's *behind* it, which only becomes visible once the element itself stops hiding that blur behind an opaque background. Get the transparency right and you've got the effect. Forget that it also opens a new stacking context, and a `z-index` you were sure would win quietly loses to a scope you didn't know existed. And treat the blur radius as a performance budget, not a free design knob — the frame it costs shows up on someone's phone, not in your editor.\n\nHave you shipped a frosted panel that turned out to be a flat one for a sprint before anyone noticed? What gave it away — the missing blur, or the z-index fight?\n\n\u003C!-- related:start -->\n\n## 📚 Read next\n\n- [The CSS Property That Fixes Dark Mode's Ugly White Boxes](https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fcss-color-scheme-native-dark-mode-form-controls)\n- [One CSS Property Replaces Your Checkbox Hack](https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fcss-accent-color-native-form-control-tinting)\n- [You reach for Sass to mix colors. `color-mix()` does it natively.](https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fcss-color-mix-native-color-mixing)\n\n\u003C!-- related:end -->\n\n---\n\n🚀 **Want more like this?** Every guide, playground, and quiz lives on **[bestpractic.org](https:\u002F\u002Fbestpractic.org\u002F)** — open it and **[sign up free](https:\u002F\u002Fbestpractic.org\u002F)** so the next one finds you.\n\n*Thanks for reading! Let's stay connected:*\n\n- ⭐ **GitHub** — follow me and star the projects: [github.com\u002Fparsajiravand](https:\u002F\u002Fgithub.com\u002Fparsajiravand)\n- 💬 **Discord** — join the frontend best-practices community: [discord.gg\u002Fd9KRhuAwQ](https:\u002F\u002Fdiscord.gg\u002Fd9KRhuAwQ)\n- 📸 **Instagram** — frontend best practices, daily: [@bestpractice___](https:\u002F\u002Fwww.instagram.com\u002Fbestpractice___\u002F)",{"title":111,"canonical":280,"description":281},"https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fcss-backdrop-filter-frosted-glass","backdrop-filter looks like a one-line copy from a Codepen: blur(20px), ship the frosted navbar. Half the time it renders as a plain flat panel instead — because backdrop-filter blu","01a0ec73-013a-70ca-bcf4-09d7721f3ef1",{"id":284,"locked":18},"01a0ec73-03a8-772c-9854-5ca470bfd303",[286],{"id":45,"slug":46,"title":48,"_count":287},{"questions":51},[289],{"locale":13,"slug":46},{"id":45,"slug":46,"title":48,"_count":291,"questionCount":51},{"questions":51}]