跳到主要內容

當絕對定位遇上層疊上下文

· 閱讀需 3 分鍾

css中position: absolute可以將元素指定為絕對定位,那麼絕對定位元素的幾何位置是相對於誰計算呢?

MDN上的描述是:

絕對定位元素相對於最近的非 static 祖先元素定位。當這樣的祖先元素不存在時,則相對於ICB(inital container block, 初始包含塊)。

也即是說,絕對定位元素應該相對其position為非static的最近祖先定位,或者這樣的祖先不存在時相對初始包含快(一般為body)定位。而position默認為static。

但似乎有時候也有例外。

今天想在一個scroller組件中使用絕對定位突破到更頂層,但意外的發現,即使從該元素的父元素到body都沒有指定position屬性,它竟然仍是相對scroller容器定位而不是body或者更上層的具有position: relative屬性的元素。

實驗了半天發現是因為scroller使用了css的transform屬性來變換滾動元素的位置以提升性能。而這直接導致了具有有效transform屬性的元素成了絕對定位元素的基準。

考慮如下html:

<div style="line-height: 50px;">
<style>
.relative-container {
background: lightcoral;
position: relative;
height: 300px;
}
.midware {
background: lightcyan;
height: 200px;
}
.absolute-block {
background: black;
height: 30px;
position: absolute;
top: 0;
width: 30px;
}
</style>
<div class="relative-container">
------把下面的div撑下去一点方便观察差异-------
<div class="midware">
<div class="absolute-block"></div>
</div>
</div>
</div>
------把下面的div撐下去一點-------

如上,absolute-block成功突破了midwaretop: 0是相對於relative-container而不是其直接父元素midware。但是當我們為midware添加transform屬性後:

.midware {
background: lightcyan;
height: 200px;
transform: translateZ(0);
}
------把下面的div撐下去一點-------

absolute-block已經相對其父元素midware定位了!但midwareposition並沒有被顯示指定。transform設置為其他有效值效果也一樣。

為了測試transform屬性是否隱式改變了position屬性,我添加了如下代碼:

const el = document.querySelector('.midware');
console.log(getComputedStyle(el).position); // static

並沒有。這個現象應該是由其他機制引起的。

最後查了下資料,有人說是由層疊上下文導致的。但又不是所有的層疊上下文都會造成這樣的影響,不同內核的瀏覽器也有不同的表現。所以應該將這個特性當作bug來對待?

參考:
不受控制的 position:fixed