CSS Filter 影響子元素的解決辦法

透過 filter 我們可以為元素加上不同的效果,像是模糊,色彩偏移等(filter 介紹)。但我們可能會發現一個奇怪的現象:

filter 導致 position 失效

在這個範例中,我們先設定兩個 .box,再分別在子元素 .box div 加上 position:fixed,第二個.box再單獨設定filter:grayscale(1)

1
2
3
4
5
6
7
<div class="box">
<div style="position:fixed">I am fixed on scroll</div>
</div>

<div class="box" style="filter:grayscale(1)">
<div style="position:fixed">I move with the scroll</div>
</div>

從下面的 CodePen 範例中,我們可以發現向下滾動後,加上了 filter 的 .box div 不會跟著移動。

See the Pen by 蔡蔡 Mavis (@0430shinyu) on CodePen.

會這樣改變的原因是因為,加上了 filter 後子元素不再以 Viewport 做為基準,
而是以設定了 filter 的 .box 為基準。

更詳細的說明可以參考 W3C 的解釋,大意就是當 filter 的屬性不是 none 時,除非 filter 是設定在根節點(HTML)上,不然會為有設定 position:absoluteposition:fixed 的子元素產生一個新的容器,使得這些子元素的定位基準變成這些新的容器。

另外,這個現象也會發生在 transform 上喔!

解決方案
我們可以透過將 filter 設定在子元素來解決。

1
2
3
<div class="box">
<div style="position:fixed;filter:grayscale(1)">I move with the scroll</div>
</div>

See the Pen css-filter-child-position-resolve by 蔡蔡 Mavis (@0430shinyu) on CodePen.

這樣一來子元素的定位就不會被影響了~

filter 影響子元素樣式

我們可能會想透過 filter 為我們的背景圖片加上模糊(blur)效果:

1
2
3
<div class="box" style="filter:blur(3px)">
<p>Cute Dog</p>
</div>

但實作後卻會發現圖片上的字也一起變模糊了

See the Pen by 蔡蔡 Mavis (@0430shinyu) on CodePen.

解決方案
我們可以將模糊效果改設定在偽元素上來避免這個問題。
(記得也要拿掉在.box設定的 filter)

1
2
3
4
5
6
7
8
9
10
.box::before {
content: "";
width:100%;
height:100%;
position: absolute;
z-index: -1;
background: url("https://images.unsplash.com/photo-1552053831-71594a27632d?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=624&q=80")
50% 30%;
filter: blur(3px);
}

See the Pen css-filter-child-style by 蔡蔡 Mavis (@0430shinyu) on CodePen.

參考資料

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

CSS:filter(滤镜)修饰父元素背景,影响子元素问题解决


CSS Filter 影響子元素的解決辦法
https://shinyu0430.github.io/2021/09/18/filterchildproblem/
作者
Mavis Tsai
發布於
2021年9月18日
許可協議