背景
近期遇到一個問題,當使用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