情景重现
在做移动端菜单的时候发现设置 will-change:transform
会导致 position
为 fixed
的子元素相对于父级元素来定位,一个简答的例子
<!DOCTYPE html><html lang="en"> <head> <meta charset="UTF-8" /> <title>Document</title> <style> .container { width: 100%; height: 100px; background: #333; will-change: transform; } .child { position: fixed; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.3); } </style> </head> <body> <div class="container"> <div class="child"></div> </div> </body></html>
运行结果中child 元素不是相对于浏览器窗口来定位
原因分析
fixed 的定义是生成绝对定位的元素,相对于浏览器窗口进行定位
will-change属性为 web 开发者提供了一种告知浏览器该元素会有哪些变化的方法,这样浏览器可以在元素属性真正发生变化之前提前做好对应的优化准备工作。这种优化可以将一部分复杂的计算工作提前准备好,使页面的反应更为快速灵敏,虽然好用,但是不要滥用
在w3.org有一句话“If any non-initial value of a property would cause the element to generate a containing block for fixed-position elements, specifying that property in will-change must cause the element to generate a containing block for fixed-position elements.”
大致的意思是使用 will-change
会导致元素产生新的层叠容器,为了更好渲染不导致整个页面重绘
但是特殊的是,使用 will-change:opacity
却不会导致 position:fixed
失效,所以**导致这个原因应该不是 will-change
属性,应该是 transform
。**如果在父元素使用 transform 属性,也会导致子元素的 position:fixed
失效
最简单的解决方法是,如果使用到 transform 动画时候,尽量不要在 transform 的元素上的子元素使用 fixed 布局或者 absolute 布局