CSS Backdrop-Filter Does Not Update When Content Behind It Moves

CSS: Workaround to backdrop-filter?

As of Chrome M76, backdrop-filter is now shipped, unprefixed, and without a needed flag.

https://web.dev/backdrop-filter/

NOTE: (since this answer keeps getting downvoted because Mozilla hasn’t yet shipped it): this feature is available in Safari, Chrome, and Edge, but not yet in Firefox. Mozilla is planning to ship it very soon, but hasn’t yet. So this answer doesn’t contain a “workaround” but simply more information about which browsers require a workaround. Which still seems like useful information.

Why does applying a CSS-Filter on the parent break the child positioning?

If we refer to the specification we can read:

A value other than none for the filter property results in the
creation of a containing block for absolute and fixed positioned
descendants unless the element it applies to is a document root
element in the current browsing context. The list of functions are
applied in the order provided.

This means that your position:fixed element will be positioned relatively to the filtered container and no more the viewport. In other words, it's still fixed but inside its new containing block (the filtered container)

Here is a simplified version to illustrate the issue:

.container {
display: inline-block;
width: 200px;
height: 200vh;
border: 1px solid;
}

.container>div {
position: fixed;
width: 100px;
height: 100px;
background: red;
color: #fff;
}
<div class="container">
<div>I am fixed on scroll</div>
</div>

<div class="container" style="filter:grayscale(1);">
<div>I move with the scroll</div>
</div>

How can I change the backdrop filter I have set in CSS with JavaScript?

The code you have here: parseInt(view.style.backdropFilter)+'blur('+1+'px)', if we breakdown what it will get-- the value at view.style.backdropFilter, which will be something like "blur(3px)", which will evaluate to NaN when parsed as an integer. You then add this to some numbers an strings, which is essentially NaN+'blur('+1+'px)', which will evaluate to "NaNblur(1px)", which obviously won't work.

Your example involves a lot of code-- not quite a minimal, reproducible example. As such, I just created a small example of how to accomplish this below. I stored the current blur level in a data attribute to avoid having to try to ascertain it from the current value each time. Then I increment it, update the dataset, and update the element.style.backdropFilter value with blur(${increasedLevel}px:

function increaseBlur() {
const overlay = document.querySelector('.overlay');
const currentLevel = parseInt(overlay.dataset.blurlevel, 10);
const increasedLevel = currentLevel + 1;
overlay.dataset.blurlevel = increasedLevel;
overlay.style.backdropFilter = `blur(${increasedLevel}px)`;
}
.wrapper {
position: relative;
}

.overlay {
position: absolute;
top: 0;
bottom: 0;
right: 0;
left: 0;
}
<div class="wrapper">
<h1>Text</h1>
<div class="overlay" data-blurlevel="0" style="backdropFilter: 'blur(0px')"></div>
</div>
<button onclick="increaseBlur()">increase</button>


Related Topics



Leave a reply



Submit