5、任務三——如何解決高度坍塌問題?——BFC模式


  來源:那些年我們一起清除的浮動

     CSS|Float知多少(微信)

       學習塊格式化上下文

         hasLayout IE瀏覽器bug的來源  (微信)

 

 

  問題引起是2016IFE春季問題的任務三,總的父元素parent包含三個浮動的子元素,容器的高度不能自動伸長以適應內容的高度,出現了高度坍塌問題。 

代碼如下:              

<div class="parent">
    <div class="left"></div>
    <div class="center"></div>
    <div class="right"></div>
</div>
    .parent{
    margin:20px;
     background-color:red;
        border:solid 2px black;
    }
    .left,.right,.center{
        float:left;
        width:200px;
        height:200px;
        background-color:yellow;
        border:solid 2px blue;
    }                 

高度塌陷

   (最上面的一條黑線就是parent元素了,可以看到它的高度為0

    原因就是浮動使子元素脫離文檔流,父元素無法感知子元素的存在,而且父元素內部不存在其他處於文檔流中的元素,也就表現為高度為0

          既然是由浮動引起的,就用clear屬性清除浮動吧,其實這是錯誤的,clear屬性規定的是元素哪一側不允許有其他浮動元素,但是我們並不是想讓父元素周圍沒有其他浮動元素,而是減少浮動帶來的影響,也就是使浮動元素閉合。

          先來看一下閉合浮動的方法:

      1)添加額外標簽

         通過在浮動元素末尾添加一個空的標簽,例如 <div style=”clear:both”></div>,其他標簽br等亦可。      

<div class="wrap" id="float1">

  <h2>1)添加額外標簽</h2>

  <div class="main left">.main{float:left;}</div>

  <div class="side left">.side{float:right;}</div>

  <div style="clear:both;"></div>

</div>

<div class="footer">.footer</div>

                      優雅的 Demo

         優點:通俗易懂,容易掌握

         缺點:可以想象通過此方法,會添加多少無意義的空標簽,有違結構與表現的分離,在后期維護中將是噩夢,這是堅決不能忍受的,所以你看了這篇文章之后還是建議不要用了吧。

      2)使用 br標簽和其自身的 html屬性

        這個方法有些小眾,br 有 clear=“all | left | right | none” 屬性

<div class="wrap" id="float2">

  <h2>2)使用 br標簽和其自身的 html屬性</h2>

  <div class="main left">.main{float:left;}</div>

  <div class="side left">.side{float:right;}</div>

  <br clear="all" />

</div>

<div class="footer">.footer</div>

                    優雅的 Demo

         優點:比空標簽方式語義稍強,代碼量較少

       缺點:同樣有違結構與表現的分離,不推薦使用

       3)父元素設置 overflow:hidden

       通過設置父元素overflow值設置為hidden;在IE6中還需要觸發 hasLayout ,例如 zoom:1;

<div class="wrap" id="float3" style="overflow:hidden; *zoom:1;">

  <h2>3)父元素設置 overflow </h2>

  <div class="main left">.main{float:left;}</div>

  <div class="side left">.side{float:right;}</div>

</div>

<div class="footer">.footer</div>

                    優雅的 Demo

                優點:不存在結構和語義化問題,代碼量極少

       缺點:內容增多時候容易造成不會自動換行導致內容被隱藏掉,無法顯示需要溢出的元素;04年POPO就發現overflow:hidden會導致中鍵失效,這是我作為一個多標簽瀏覽控所不能接受的。所以還是不要使用了

      4)父元素設置 overflow:auto 屬性

       同樣IE6需要觸發hasLayout,演示和3差不多

       優點:不存在結構和語義化問題,代碼量極少

       缺點:多個嵌套后,firefox某些情況會造成內容全選;IE中 mouseover 造成寬度改變時會出現最外層模塊有滾動條等,firefox早期版本會無故產生focus等, 請看 嗷嗷的 Demo ,不要使用

      5)父元素也設置浮動

       優點:不存在結構和語義化問題,代碼量極少

       缺點:使得與父元素相鄰的元素的布局會受到影響,不可能一直浮動到body,不推薦使用

      6)父元素設置display:table

        優雅的 Demo

        優點:結構語義化完全正確,代碼量極少

        缺點:盒模型屬性已經改變,由此造成的一系列問題,得不償失,不推薦使用

      7)使用:after 偽元素

        需要注意的是 :after是偽元素(Pseudo-Element),不是偽類(某些CSS手冊里面稱之為“偽對象”),很多閉合浮動大全之類的文章都稱之為偽類,不過csser要嚴謹一點,這是一種態度。

        由於IE6-7不支持:after,使用 zoom:1觸發 hasLayout。

          該方法源自於: How To Clear Floats Without Structural Markup

        最后精簡的代碼如下:

           .clearfix:after {content:".";            生成內容作為最后一個元素,至於content里面是點還是其他都是可以的        

                      display:block;         使生成的元素以塊級元素顯示,占滿剩余空間;

                      height:0;               避免生成內容破壞原有布局的高度。

                      visibility:hidden;      使生成的內容不可見,並允許可能被生成內容蓋住的內容可以進行點擊和交互;

                      clear:both;             閉合浮動

                  }

          .clearfix { *zoom:1; }                    觸發IE hasLayout

小結

    通過對比,我們不難發現,其實以上列舉的方法,無非有兩類:

    其一,通過在浮動元素的末尾添加一個空元素,設置 clear:both屬性,after偽元素其實也是通過 content 在元素的后面生成了內容為一個點的塊級元素;

    其二,通過設置父元素 overflow 或者display:table 屬性來閉合浮動,我們來探討一下這里面的原理。

 

      原理就是 Block formatting contexts (塊級格式化上下文),以下簡稱 BFC,它是CSS2.1規范定義的,是頁面 CSS 視覺渲染的一部分,用於決定塊盒子的布局及浮動相互影響范圍的一個區域。簡單來說,BFC 就是一種屬性,這種屬性會影響着元素的定位以及與其兄弟元素之間的相互作用。

下面的情況會產生新的BFC:

  • 根元素或其它包含它的元素
  • 浮動 (元素的 float 不為 none)
  • 絕對定位元素 (元素的 position 為 absolute 或 fixed)
  • 行內塊 inline-blocks (元素的 display: inline-block)
  • 表格單元格 (元素的 display: table-cell,HTML表格單元格默認屬性)
  • 表格標題 (元素的 display: table-caption, HTML表格標題默認屬性)
  • overflow 的值不為 visible的元素
  • 彈性盒 flex boxes (元素的 display: flex 或 inline-flex)

      其中,最常見的就是overflow:hidden、float:left/right、position:absolute。也就是說,每次看到這些屬性的時候,就代表了該元素已經創建了一個BFC了。

    需要注意的是,display:table 本身並不會創建BFC,但是它會產生匿名框(anonymous boxes  沒有名字不能被選擇器選中的盒,它們的所有屬性都為inherit或初始默認值;),而匿名框中的display:table-cell可以創建新的BFC,換句話說,觸發塊級格式化上下文的是匿名框,而不是display:table。所以通過display:table和display:table-cell創建的BFC效果是不一樣的。

 BFC 特性     

  1. 內部的盒會在垂直方向一個接一個排列(可以看作BFC中有一個的常規流);
  2. 處於同一個BFC中的元素相互影響,可能會發生外邊距疊加,如果這兩個相鄰的塊框不屬於同一個塊級格式化上下文,那么它們的外邊距就不會疊加。;
  3. 每個元素的margin box的左邊,與容器塊border box的左邊相接觸(對於從左往右的格式化,否則相反)。即使存在浮動也是如此;
  4. BFC就是頁面上的一個隔離的獨立容器,容器里面的子元素不會影響到外面的元素,反之亦然;
  5. 計算BFC的高度時,考慮BFC所包含的所有元素,連浮動元素也參與計算;
  6. 浮動盒區域不疊加到BFC上;

 

    BFC包含創建該上下文元素的所有子元素,但不包括創建了新BFC的子元素的內部元素,也就是一個元素不能同時存在於兩個BFC中。

 

      通俗地來說:創建了 BFC的元素就是一個獨立的盒子,里面的子元素不會在布局上影響外面的元素,反之亦然,同時BFC仍然屬於文檔中的普通流。

從實際代碼來分析BFC

實例一

<style>
    * {
        margin: 0;
        padding: 0;
    }
    .left{
        background: #73DE80;    /* 綠色 */
        opacity: 0.5;
        border: 3px solid #F31264;
        width: 200px;
        height: 200px;
        float: left;
    }
    .right{                     /* 粉色 */
        background: #EF5BE2;
        opacity: 0.5;
        border: 3px solid #F31264;
        width:400px;
        min-height: 100px;
    }
    .box{
        background:#888;
        height: 100%;
        margin-left: 50px;
    }
</style>
<div class='box'>
    <div class='left'> </div>
    <div class='right'> </div>
</div>

顯示效果:

實例一

  綠色框('#left')向左浮動,它創建了一個新BFC,但暫時不討論它所創建的BFC。由於綠色框浮動了,它脫離了原本normal flow的位置,因此,粉色框('#right')就被定位到灰色父元素的左上角(特性3:元素左邊與容器左邊相接觸),與浮動綠色框發生了重疊。

  同時,由於灰色框('#box')並沒有創建BFC,因此在計算高度的時候,並沒有考慮綠色框的區域,發生了高度坍塌,這也是常見問題之一。

實例二

現在通過設置overflow:hidden來創建BFC閉合浮動,再看看效果如何。

.BFC{
    overflow: hidden;
}

<div class='box BFC'>
    <div class='left'> </div>
    <div class='right'> </div>
</div>

 

實例二

  灰色框創建了一個新的BFC后,高度發生了變化,計算高度時它將綠色框區域也考慮進去了(特性5:計算BFC的高度時,浮動元素也參與計算);

而綠色框和紅色框的顯示效果仍然沒有任何變化。

實例三

現在,現將一些小塊添加到粉色框中,看看效果:

<style>
    .little{
        background: #fff;
        width: 50px;
        height: 50px;
        margin: 10px;
        float: left;
    }
</style>

<div class='box BFC'>
    <div class='left'> </div>
    <div class='right'>
        <div class='little'></div>
        <div class='little'></div>
        <div class='little'></div>
    </div>
</div>

 

實例三

  由於粉色框沒有創建新的BFC,因此粉色框中白色塊受到了綠色框的影響,被擠到了右邊去了(特性6:浮動盒區域不疊加到BFC上)。先不管這個,看看白色塊的margin,發生了外邊距疊加。

實例四

利用同實例二中一樣的方法,為粉色框創建BFC,防止與浮動元素(綠色框)重疊:

<div class='box BFC'>
    <div class='left'> </div>
    <div class='right BFC'>
        <div class='little'></div>
        <div class='little'></div>
        <div class='little'></div>
    </div>
</div>

 

實例四

  一旦粉色框創建了新的BFC以后,粉色框就不與綠色浮動框發生重疊了,同時內部的白色塊處於隔離的空間(特性4:BFC就是頁面上的一個隔離的獨立容器),白色塊也不會受到綠色浮動框的擠壓。

總結

  以上就是BFC的分析,BFC的概念比較抽象,但通過實例分析應該能夠更好地理解BFC。在實際中,利用BFC可以閉合浮動(實例二),防止與浮動元素重疊(實例四)。同時,由於BFC的隔離作用,可以利用BFC包含一個元素,防止這個元素與BFC外的元素發生margin collapse。

 

那么到底為什么坍塌?

  float 脫離了普通流,並且創建了新的BFC,而父元素不具備產生 BFC 的條件,所以它的高度為0。

如何解決?

  通過了解BFC的特性我們知道,BFC會把它包含的浮動元素高度也算在里面,也就是閉合浮動。拿 overflow: auto 舉例:overflow: auto 並不會閉合浮動,而是 overflow: auto 會創建一個新的BFC,免浮動的元素侵入其他元素。

   IE6-7有一個特有的屬性就是haslayout當一個元素的hasLayout屬性值為true時,我們說這個元素有一個布局(layout)它負責對自己和可能的后代元素進行尺寸計算和定位,當屬性值為false時,它的尺寸和位置由最近擁有布局的祖先元素控制。

  很多情況下,把 hasLayout的狀態改成true 可以解決很大部分ie下顯示的bug。 hasLayout屬性不能直接設定,通過設定一些特定的css屬性來觸發並改變 hasLayout 狀態。

  元素hasLayout而導致的問題其實一般都很容易發現:往往是內容出現錯位甚至完全不可見。 如:當一個元素內含浮動或絕對定位的內容時,它通常會表現出奇怪和錯誤的行為

  一般如果是因為layout而引起的顯示不符期望效果的話,在ff下會表現正常,而在ie下會出現錯誤。這個時候可以嘗試觸發父容器及其中的子容器的haslayout屬性,通常可以通過加上zoom: 1;來調試。直到找到了產生問題的元素,再進行針對性的修正。最好的辦法是對這個元素設置尺寸屬性。但是,有時不便指定尺寸屬性的情況下,就只能尋找替代方案了。對於ie7 ,最好的辦法是設置最小高度屬性為0;這個技術是無害的,因為0本來就是這個屬性的初始值。而且沒有必要對其他瀏覽器隱藏這個屬性。而對於ie6和更早版本中觸發一個元素hasLayout的方法是在overflow屬性是visible的情況下設置這個元素的高度屬性為1%,然后對其他瀏覽器隱藏這個設置。這種技術就是著名的Holly hack。

觸發hasLayout的條件:

  • position: absolute 
     
  • float: left|right 
     
  • display: inline-block 
     
  • width: 除 “auto” 外的任意值 
     
  • height: 除 “auto” 外的任意值 (例如很多人閉合浮動會用到 height: 1%  ) 
     
  • zoom: 除 “normal” 外的任意值
     
  • writing-mode: tb-rl

在 IE7 中,一些額外的屬性也可以觸發該屬性:

  • min-height: (任何值)

    max-height: (任何值除了none)

    min-width: (任何值)

    max-width: (任何值除了none)

  • overflow: hidden|scroll|auto ( 這個屬性在IE之前版本中沒有觸發 layout 的功能。 )
     
  • overflow-x|-y: hidden|scroll|auto (CSS3 盒模型中的屬性,尚未得到瀏覽器的廣泛支持。他們在之前IE版本中同樣沒有觸發 layout 的功能)

 綜上所述:

 在支持BFC的瀏覽器(IE8+firefoxchromesafari)通過創建新的BFC閉合浮動;

 在不支持 BFC的瀏覽器 (IE6-7),通過觸發 hasLayout 閉合浮動。

 


免責聲明!

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



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