Collectives™ on Stack Overflow
Find centralized, trusted content and collaborate around the technologies you use most.
Learn more about Collectives
Teams
Q&A for work
Connect and share knowledge within a single location that is structured and easy to search.
Learn more about Teams
I have a
div.outer
and inside a
div.inner
, both with
position: absolute;
and
backdrop-filter: blur(8px);
.
https://jsbin.com/nihakiqocu/1/edit?html,css,output
Safari (left) gives the desired result – both divs blur what's behind them.
Chrome (right), however, only applies the blur of
div.outer
:
I have a solution: adding another div inside
div.outer
and moving
backdrop-filter: blur(8px);
to that new div.
However, I would appreciate a solution that doesn't require changing the DOM from the first jsbin. Also, does anybody know what is causing this – is it a Chrome bug?
https://jsbin.com/rasudijame/1/edit?html,css,output
PS: it works on iOS's Chrome, but not on Android's Chrome and also not on Mac OS's Chrome
–
Place the backdrop filter on css pseudo element. This allows nested backdrop filters. Also you can use
z-index: -1;
to position your backdrop behind your elemets
div {
height: 100px;
width: 100px;
.wrapper {
position: absolute;
.outer, .inner {
position: relative;
.outer::before {
content: '';
position: absolute;
width: 100%;
height: 100%;
-webkit-backdrop-filter: blur(8px);
backdrop-filter: blur(8px);
.outer {
background: rgba(255, 0, 0, .5);
.inner::before {
content: '';
position: absolute;
width: 100%;
height: 100%;
-webkit-backdrop-filter: blur(8px);
backdrop-filter: blur(8px);
.inner {
background: rgba(0, 0, 255, .5);
top: 50px;
left: 50px;
main {
position: relative;
<div class="wrapper">
<div class="outer">
<div class="inner"></div>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusamus in id quos, est voluptatibus minus porro sunt totam quod commodi odit maxime similique, dolorum aut quo atque. Deleniti, voluptas animi.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusamus in id quos, est voluptatibus minus porro sunt totam quod commodi odit maxime similique, dolorum aut quo atque. Deleniti, voluptas animi.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusamus in id quos, est voluptatibus minus porro sunt totam quod commodi odit maxime similique, dolorum aut quo atque. Deleniti, voluptas animi.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusamus in id quos, est voluptatibus minus porro sunt totam quod commodi odit maxime similique, dolorum aut quo atque. Deleniti, voluptas animi.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusamus in id quos, est voluptatibus minus porro sunt totam quod commodi odit maxime similique, dolorum aut quo atque. Deleniti, voluptas animi.</p>
</main>
And here is codepen
–
–
–
This answer completes the one from @Michał (which worked for me). Short answer: Chrome voluntarily prevents nested backdrop filters from stacking.
Why Chrome behaves this way
A very similar issue has been reported on chromium bugs tracker. Quoting an answer to this bug report:
The backdrop-filter will filter everything behind it, up to the "Backdrop Root", which is formed by several triggers. One of those triggers is another backdrop-filter element.
So basically, when you add backdrop-filter
to an element, it becomes the new backdrop root: nested backdrop filters will NOT apply to any of its ancestors, because they cannot "see" above the root.
<elem1>
<!-- Here, backdrop filter will apply to elem1, -->
<!-- as it is an ancestor of elem2 -->
<elem2 style="backdrop-filter: ...">
<!-- Here, backdrop filter will apply to elem2, -->
<!-- but not elem1, as elem2 is now the new Backdrop root -->
<elem3 style="backdrop-filter: ...">
</elem3>
</elem2>
</elem1>
Chrome actually follows a W3C recommendation (or so it seems). If you have the motivation, you can read the full reason why this behavior exist at this W3C draft.
Why the accepted answer works
The :before
is a pseudo element, which means it has no child. Thus, even if it becomes a backdrop root, it will not block nested filters from applying to its ancestors.
Why it works on other browsers
As of May 2023, I was able to test this behavior on Chrome, Safari and Firefox. Only Chrome seems to follow this W3C draft, as elements were correctly blurred on Safari and Firefox. However, Safari and Firefox are deviating from spec according to the bug report answers.
Summary
If you want an element with a backdrop filter to allow nested backdrops (for example, a transparent nav-bar with a drop menu that both have a blur/transparent effect), you should apply the filter to a pseudo element, as @Michał suggested:
/* replace */
.parent {
backdrop-filter: /*...*/;
/* with */
.parent::before {
content: '';
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
backdrop-filter: /*...*/;
z-index: -1;
Note: you only need to to this if the parent container has nested elements with a backdrop filter set, not on "leaves" elements.
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.