Fixed 定位的失效问题
通常情况下position: fixed元素相对于视口定位,但是某些情况下,比如祖先元素设置了transform、filter、perspective、will-change: transform的时候,子元素的固定定位会失效,不在相对于视口定位,而是相对于该祖先元素定位,约等于绝对定位。
比如:
<div style="position: fixed; top: 50vh; right: 0; width: 10vh; height: 10vh; background-color: lightblue"></div>
<div style="transform: translate(0, 0); padding-top: 25vh">
<div style="position: fixed; top: 10vh; width: 10vh; height: 10vh; background-color: lightcoral"></div>
</div>
<div style="filter: blur(0); padding-top: 25vh">
<div style="position: fixed; top: 10vh; width: 10vh; height: 10vh; background-color: lightcyan"></div>
</div>
<div style="perspective: 0; padding-top: 25vh">
<div style="position: fixed; top: 10vh; width: 10vh; height: 10vh; background-color: lightgoldenrodyellow"></div>
</div>
<div style="will-change: transform; padding-top: 25vh">
<div style="position: fixed; top: 10vh; width: 10vh; height: 10vh; background-color: lightgray"></div>
</div>
第一个元素定位正常,但后面的元素定位异常,这是因为这些元素的父元素因为特定的 CSS 属性被放在新的图层之中。
一般情况下,当我们发现了固定定位异常时,排查祖先元素是否含有上述的 CSS 属性即可。但有一种情况,虽然在浏览器的 CSS 面板中看不到上述属性,但元素依然处于不同的图层中。这就是当元素被执行过animate且执行了上述 CSS 属性的动画。
比如:
<div id="moving">
<div style="position: fixed; top: 0; width: 10vh; height: 10vh; background-color: lightblue"></div>
</div>
<script>
let moving = window.document.getElementById('moving');
moving.animate([{ transform: 'translate(0, 0)' }, { transform: 'translate(0, 50vh)' }], { duration: 1000, fill: 'forwards' });
</script>
如果运行上面的代码,可以看到固定定位的元素在跟随父元素移动,同时此时看到浏览器的 CSS 面板中父元素并没有 transform 相关属性。
不得不说,好坑啊。