背景
近期遇到一个问题,当使用React Drawer 抽屉时,抽屉中position:fixed
不表现为基于可视窗口定位,而是基于该抽屉进行定位,很好奇这种设定,于是基于该内容进行了一些探索。
探索过程
- React Drawer实现方式为transform
- 当
position:fixed
的祖先元素为transform时,定位容器由视口改为该祖先。 - 不仅仅在transform中
position:fixed
失效,在所有堆叠上下文(Stacking Context)均会导致position:fixed失效。【MDN理论】 - 并非所有堆叠上下文(Stacking Context)下
position:fixed
都失效,仅在:- transform 属性值不为 none 的元素
- perspective 值不为 none 的元素
- will-change 中指定了任意 CSS 属性
- filter 不为 none
- 设置了 transform-style: preserve-3d 的元素
- 不同浏览器的表现也不同,以上五种情况仅在Chrome中表现该特性
堆叠上下文(Stacking Context)
堆叠上下文(Stacking Context):堆叠上下文是 HTML 元素的三维概念,这些 HTML 元素在一条假想的相对于面向(电脑屏幕的)视窗或者网页的用户的 z 轴上延伸,HTML 元素依据其自身属性按照优先级顺序占用层叠上下文的空间。
如何创建堆叠上下文:
- 根元素 (HTML)
- z-index 值不为 "auto"的 绝对/相对定位,
- 一个 z-index 值不为 "auto"的 flex 项目 (flex item),即:父元素 display: flex|inline-flex,
- opacity 属性值小于 1 的元素(参考 the specification for opacity),
- transform 属性值不为 "none"的元素,
- mix-blend-mode 属性值不为 "normal"的元素,
- filter值不为“none”的元素,
- perspective值不为“none”的元素,
- isolation 属性被设置为 "isolate"的元素,
- position: fixed
- 在 will-change 中指定了任意 CSS 属性,即便你没有直接指定这些属性的值
- -webkit-overflow-scrolling 属性被设置 "touch"的元素
结论
Chrome中问题结论:
在Chrome(Blink内核)中,
position:fixed
在:
- 祖先元素为transform 属性值不为 none 的元素
- perspective 值不为 none 的元素
- will-change 中指定了任意 CSS
- filter 不为 none
- 设置了 transform-style: preserve-3d 的元素
情况下,定位容器由视口改为该祖先。
不同浏览器position:fixed
表现:
CSS | Chrome | Safari(Mac) | FireFox |
---|---|---|---|
z-index 值不为 "auto"的 绝对/相对定位 | |||
一个 z-index 值不为 "auto"的 flex 项目 (flex item) | |||
opacity 属性值小于 1 的元素 | |||
transform 属性值不为 "none"的元素 | 失效 | 失效 | 失效 |
mix-blend-mode 属性值不为 "normal"的元素 | |||
filter值不为“none”的元素 | 失效 | 失效 | |
perspective值不为“none”的元素 | 失效 | 失效 | |
isolation 属性被设置为 "isolate"的元素 | |||
position: fixed | |||
在 will-change 中指定了任意 CSS 属性 | 失效 | 失效 | |
-webkit-overflow-scrolling 属性被设置 "touch"的元素 | |||
设置了 transform-style: preserve-3d 的元素 | 失效 | 失效 |
position:fixed
不同表现(在不同浏览器中打开) DEMO
网友评论