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.
backdrop-filter
has poor support: caniuse. – Durant-webkit-
prefix? – Durant