淺析父元素設置transform時子元素position:fixed失效的問題


  今天遇到一個現象,設置了 position:fixed; 但是發現其行為卻隨文檔流滾動,而不是相對於 viewport 固定在某處,所以查了一下,發現是個知識點。

一、現象背景

  我理解的fixed元素是這樣的:摘自 CSS布局基礎

固定定位與absolute定位類型類似,但它的相對移動的坐標是視圖(屏幕內的網頁窗口)本身。

由於視圖本身是固定的,它不會隨瀏覽器窗口的滾動條滾動而變化,除非你在屏幕中移動瀏覽器窗口的屏幕位置,或改變瀏覽器窗口的顯示大小,因此固定定位的元素會始終位於瀏覽器窗口內視圖的某個位置,不會受文檔流動影響,這與background-attachment:fixed;屬性功能相同。

  但是在《CSS為什么這么難學》這篇文章中,作者提到了一個“黑魔法”:如何讓fixed元素不再以viewport為定位參考對象,而是以父容器為參考對象。這下我算是get到了一個技能。

  為什么fixed元素的父元素加了transform就會以父元素為參考對象?

  詳細的 demo 如下:

<div class='parent'> parent <div class="txt-box">text</div> <div class='fixed'>fixed</div> </div> .parent{ width: 200px; height: 300px; background: yellow; transform: scale(1); overflow: auto;
} .fixed { position: fixed; width: 100%; left: 0; top: 0; background: red;
} .txt-box{ height: 1000px;
}

  查看這個demo發現,我們在父元素設置了transform: scale(1);這個屬性,然后其子元素便以父元素為參考對象了,而且不再固定在某個地方,而是會隨着文檔流的流動而流動。

二、問題解析

  這是為什么呢?答案在設置了transform屬性的元素上,在W3c文檔上transform屬性,文檔的定義翻譯如下:

1、對於布局受CSS盒子模型控制的元素,transform屬性不會影響transformed元素周圍的內容流。

但是,溢出區域的范圍將會考慮上transform元素。這種行為類似於元素通過相對定位發生偏移時的情況。

因此,如果overflow屬性的值是`scroll``auto`的,滾動條將顯示為需要看到在可見區域外轉換的內容。

2、對於布局受CSS盒子模型控制的元素,除了配置為`none`之外,其他的`transform`屬性值都會創建堆棧上下文。

繪制的實現必須在其父棧上下文中它所創建的層中,如果它是帶有“z-index: 0”的定位元素,則使用相同的堆疊順序。

如果一個帶有`transform`的元素還配置了`position`屬性,那么“z-index”屬性將按照[CSS2](https://www.w3.org/TR/css-transforms-1/#biblio-css2)描述的被應用,除非“auto”被視為“0”,因為會創建新的堆棧上下文。

3、對於布局受CSS盒子模型控制的元素,除了配置為`none`之外,其他的`transform`屬性值都將導致元素成為一個包含塊,而其固定定位的后代元素都是以此object作為他們的包含塊。

4、根元素的[Fixed Backgrounds](https://www.w3.org/TR/css3-background/#fixed0)會受到該元素上配置的transform屬性的影響。

對於受transform影響的所有其他元素(例如,對它們應用transform屬性,或者對它們的任何祖先元素應用transform屬性), `background-attachment`屬性值為`fixed`的元素會被當做它好像有配置`scroll`屬性一樣。其他`background-attachment`的計算值不受影響。

  在這段介紹中我們發現transform會對fixed屬性造成影響,具體表現可以看上面的那個demo。

  簡單來說就是:應用了transform屬性的元素會導致該元素形成一個新的包含塊,然后其后代元素如果有fixed定位的屬性,那么其元素將會以該父元素作為包含塊,從而有了之前我們看到的現象。

1、在 w3c 中對 position: fixed 的[定義](https://www.w3.org/TR/css-position/#fixed-pos)如下:

Fixed positioning is similar to absolute positioning. 
The only difference is that for a fixed positioned box, 
the containing block is established by the viewport.

  大概意思就是,fixed 元素的塊級格式上下文 Block Formatting Context(BFC) 由 viewport 創建,也就是fixed 元素的 BFC 包含在根元素的 BFC 里。那以上 demo 的表現就說不過去了。為什么呢?谷歌一下,原來是父元素的 transform 在搗亂。

  再看看 w3c 對 transform 的[定義]():

For elements whose layout is governed by the CSS box model, any value other than none for the transform property also causes the element to establish a containing block for all descendants.
Its padding box will be used to layout for all of its absolute-position descendants, fixed-position descendants, and descendant fixed background attachments.

  大概意思就是,transform 屬性使元素創建了新的 BFC,所有的子元素都被包含在這個新的 BFC 內。那么設置了 position: fixed 的子元素 BFC 被包含在了 transform 元素的 BFC 里。

  BFC 和定位有什么關系呢,繼續翻 w3c,有段關於 BFC 的[定義](https://www.w3.org/TR/css-position/#def-cb):

The position and size of an element’s box(es) are sometimes computed relative to a certain rectangle, called the containing block of the element.

  元素的位置和尺寸是相對於一個確定的 BFC 計算的。所以 demo 展示的 fixed 元素位置是根據它所在的 BFC 計算的。

  除了上述說的,我還發現了另外兩個特征:

1、fixed元素不在固定在某個位置,失去了fixed元素特有的性質

2、fixed元素不會脫離文檔流,但是top等屬性依然可用。可以看例子中的top屬性,配置了top:10px;整個文檔流都往下走10px。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM