1. 前言
最近在项目开发过程中遇到了一个固定定位失效的问题,当给底部定位元素设置了position: fixed并设置了距离top和left,bottom的距离之后发现位置居然一直不正确,fixed固定定位失效了。
百度看了些文章说是父元素如果存在 transform
属性非none
或者移动端设置-webkit-overflow-scrolling
属性时会出现同样的问题
我的页面父元素未设置 transform ,就全局搜索了-webkit-overflow-scrolling,发现全局样式里设置了,百度了-webkit-overflow-scrolling导致fixed布局失效
2. 了解 -webkit-overflow-scrolling
-webkit-overflow-scrolling
属性控制元素在移动设备上是否使用滚动回弹效果,这样更自然,像是原生效果。
touch
使用具有回弹效果的滚动, 当手指从触摸屏上移开,内容会继续保持一段时间的滚动效果。继续滚动的速度和持续的时间和滚动手势的强烈程度成正比。同时也会创建一个新的堆栈上下文。
所以我们一般会在需要滚动的元素上面加:-webkit-overflow-scrolling: touch; 这个 css 属性。
但是有当子元素有 fixed 定位时,fixed 定位会失效。
原因在于:
-webkit-overflow-scrolling 属性被设置 "touch"的元素 会创建一个堆叠上下文;
这时fixed 定位元素会由屏幕视口改为该祖先元素。所以会看到定位元素随着页面滚动而飞掉。
什么是堆叠上下文?
堆叠上下文(Stacking Context):堆叠上下文是 HTML 元素的三维概念,这些 HTML 元素在一条假想的相对于面向(电脑屏幕的)视窗或者网页的用户的 z 轴上延伸,HTML 元素依据其自身属性按照优先级顺序占用层叠上下文的空间。
概念比较抽象,简单理解,就是 生成了 Stacking Context 的元素会影响 该元素的层叠关系与定位关系
。
总之,按照上面的说法,堆叠上下文的创建,该元素会影响其子元素的固定定位。设置了 position:fixed 的子元素将不会基于 viewport 定位,而是基于这个祖先元素。
解决方法:
因为 -webkit-overflow-scrolling导致fixed基于祖先元素定位,我页面内容没有铺满整个屏幕,导致fixed定位的元素上移,所以目前我的解决的方法是,设置最外层祖先元素 height:100vh;
如果有好的解决方法很欢迎一起交流哈~
3. 关于transform非none导致的无效
MND用一句话概括了这种情况:
当元素祖先的 transform 属性非 none 时,定位容器由视口改为该祖先。
所以如果fixed失效的情况下我们也可以查看祖先元素有transform的话要改为 transform:none
4. 总结:
以上两种导致fixed方法失效的原因都是创建了堆叠上下文,该元素会影响其子元素的固定定位。设置了 position:fixed 的子元素将不会基于 viewport 定位,而是基于这个父元素。