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
Angular 2 - Jquery | Adding Styles (Top/Left) with a Mouse Position
Horizontal Sharp Background Gradient with Specific Length of First Color
How to Combine Compass with Bless
How to Break Lines in Urls in Stylesheet
Is There a List of Browser Conditionals for Use Including Stylesheets
Stack CSS Transitions Using Multiple Classes Without Overriding
CSS Columns: Target Last Child in Each Column
Background-Size Transition on Hover Causes Chrome to "Shake" Background Image
Fill a Parent Div While Maintaining a Ratio
How to Make a Div Disappear on Hover Without It Flickering When The Mouse Moves
Select All Block Level Elements with CSS