Loading...
墨滴

pmcee

2021/06/09  阅读:78  主题:橙心

CSS基础:float应用 / 盒子塌陷

float 应用

浮动盒子可以向左或向右移动,直到其外边沿接触包含块的外边沿,或接触另一个浮动盒子的外边沿。浮动盒子也会脱离常规文档流,因此常规文档流中其他块级盒子的表现,几乎当浮动盒子根本不存在一样。

一般来说,浮动元素会脱离文档流,我们会认为脱离文档流的元素不会像非浮动元素一样对其他元素造成影响。然而,由于 float 出现的原因是 为了在网页中实现文本环绕图片的效果 ,因此严格来说,当行盒子遇到浮动元素时会为浮动元素留空,造成文本环绕浮动盒子的效果,这也是为什么上面介绍时用了“几乎”的原因。

使用浮动可能会造成盒子高度塌陷的问题,具体解决方案见后面的盒子塌陷部分。本部分主要是为了利用 float 实现两种典型布局,这两种布局的作用是:

  • 实现pc端三栏布局,中间(主要内容)一栏最先渲染
  • 实现两边宽度固定,中间自适应。

一、圣杯布局

<style>
  .container {
      background-color#ddd;
      padding0 200px/* 防止center内容被两侧覆盖,padding 设置成两侧的宽度 */
      font-size40px;
  }
  .left {
      position: relative; /* 将 left 元素放到 padding-left 部分的位置 */
      width200px;
      height200px;
      margin-left: -100%/* 父元素内容的-100%,将 left 元素移到最左侧 */
      right200px;  /* 将 left 元素放到 padding-left 部分的位置 */
      background-color: tomato;
  }
  .right {
      width200px;
      height200px;
      margin-right: -200px;  /* 设置成自身宽度,且是负值,根据上篇margin负值所讲,也就是 padding-right 部分的位置会向左移,则 right 元素会平移到上一行 */
      background-color: thistle;
  }
  .center {
      width100%;
      height200px;
      background-color: turquoise;
  }
  .fl {
      float: left;
  }
  .clearfix::after {
      content"";
      display: table;
      clear: both;
  }
  /* 如果要兼容IE低版本,则加上以下代码 */
  /*
  .clearfix {
    *zoom: 1;
  }
  */

</style>
<body>
    <div class="container clearfix">
      <div class="center fl">center</div><!-- 为了让center盒子最先渲染,所以center盒子放在三个盒子的第一个位置 -->
      <div class="left fl">left</div>
      <div class="right fl">right</div>
    </div>
</body>

二、 双飞翼布局

<style>
        .fl {
            float: left;
        }
        body {
            font-size40px;
            min-width500px;
            background-color#ddd;
        }
        .left {
            width200px;
            height200px;
            background-color: tomato;
            margin-left: -100%;
        }
        .right {
            width200px;
            height200px;
            background-color: thistle;
            margin-left: -200px/* right盒子设置 margin-left: -200px ;和圣杯布局设置不一样原因是圣杯布局的margin是放在同一个外层盒子中且圣杯布局center是通过父亲元素的padding来为两侧留空,而双飞翼布局的center是通过自身来设置margin来为两侧留空的 */
        }
        .center {
            width100%;
            height200px;
            background-color: turquoise;
        }
        .c-inner {
            margin0 200px;
        }
</style>
<body>
    <div class="fl center">
      <div class="c-inner">center</div>
    </div>
    <div class="fl left">left</div>
    <div class="fl right">right</div>
</body>
圣杯布局和双飞翼布局
圣杯布局和双飞翼布局

这里只是先简单展示下 float 除文本环绕之外的应用场景。后面会针对布局进行详细的总结。

盒子塌陷

前面已经介绍过 margin 高度重叠(坍塌)的问题、float 可能造成的盒子塌陷的问题,但是都没有详细介绍如何解决该问题。因此,这里主要详细总结一下造成塌陷的原因以及相应的解决方案。

盒子塌陷
盒子塌陷

一、是什么

盒子坍塌一般都是块元素引起的问题,主要有两类。

html 元素的排列是依据盒子模型,在浏览器渲染时会出现盒子塌陷问题:

  • 第一类:盒子高度塌陷;
  • 第二类:margin 的使用造成。

不过,一般来说,面试时提到盒子塌陷问题时,通常是指由于浮动造成的盒子高度塌陷的这类问题。

二、塌陷原因

1)盒子高度塌陷原因

首先,盒子高度塌陷的大前提是,元素高度由以下两个条件决定:

  • 当前元素设置了 height 属性,则元素的高度由 height 决定;
  • 如果当前元素没有设置 height ,则元素高度由内部没有脱离文档流的元素的高度之和决定。

由此,可以推出出现盒子高度塌陷的必要条件是:

  • 当前父元素没有设置相应的 height
  • 且内部子元素脱离了文档流,导致内部没有元素可以撑起当前父元素:
    • 内部子元素使用了浮动导致内部元素脱离了文档流,且脱离文档流的元素无法撑起当前父元素。
    • 内部子元素使用了绝对定位或者固定定位脱离文档流。

2)margin 塌陷原因

主要是由于 margin 纵向重叠的特性导致:

  • 父子盒子元素 margin-top / margin-bottom 重叠(塌陷)。
  • 兄弟盒子元素塌陷:盒子的 margin-top 与另一个盒子的 margin-bottom 重叠。

三、如何解决

1)解决盒子高度塌陷

  1. 最简单,直接,粗暴的方法就是盒子大小写死,给每个盒子设定固定的height,直到合适为止,这样的好处是简单方便,兼容性好,适合只改动少量内容不涉及盒子排布的版面。缺点是非自适应,浏览器的窗口大小直接影响用户体验。

  2. 为父元素添加一个不脱离文档流的子元素。缺点是多添加了不必要的 dom 元素。

  3. 解决由于浮动造成的高度塌陷:

    • 给外部的父盒子也添加浮动,让其也脱离标准文档流,这种方法方便,但是对页面的布局不是很友好,不易维护。
    • 触发父元素的 BFC ,例如:给父盒子添加 overflow 属性。但是 overflow:auto; 有可能出现滚动条,影响美观。 overflow:hidden; 可能会带来内容不可见的问题。详见 BFC 部分的总结。
    • 将外层盒子设置为非块结构,设置为inline-block。缺点是有可能影响到文档其他元素的布局。
    • 利用 clear 属性闭合浮动:

    在这里先理清两个概念:清除浮动还是闭合浮动(Enclosing float or Clearing float)

    我是这样理解的,清除浮动指使用 clear 属性清除浮动对“我(当前使用clear 属性的元素)”的影响,闭合浮动指使内部浮动元素闭合,减少浮动带来的影响(一般是高度塌陷)。通过以下两段代码来理解应该会更好些。也就是说,闭合浮动是更好的解决方案。

   <!-- 1.清除浮动 -->
   <style>
         .container {
           border4px solid brown;
         }
         .wrap {
           border2px solid blueviolet;
         }
         .main {
           float: left;
           width100px;
           height100px;
           background-color: aqua;
         }
         .footer {
           clear: both;
         }
   
</style>
   <body>
       <div class="container">
         <div class="wrap">
           <div class="main">main</div>
         </div>
         <div class="footer">footer</div>
       </div>
   </body>
   <!-- 2.闭合浮动 -->
   <style>
         .container {
           border: 4px solid brown;
         }
         .wrap {
           border: 2px solid blueviolet;
         }
         .main {
           float: left;
           width: 100px;
           height: 100px;
           background-color: aqua;
         }
         .clearfix:after {
           content: "."; /*尽量不要为空,一般写一个点,为空可能会造成空隙*/
           height: 0; /*盒子高度为0,看不见*/
           display: block; /*插入伪元素是行内元素,要转化为块级元素*/
           visibility: hidden; /*content有内容,将元素隐藏*/
           clear: both; /* 清除浮动 */
         }
   
         .clearfix {
           *zoom: 1; /*  *只有IE6,7识别,开启hasLayout,用于兼容IE6,7 */
         }
   </style>
   <body>
       <div class="container">
         <div class="wrap clearfix">
           <div class="main">main</div>
         </div>
         <div class="footer">footer</div>
       </div>
   </body>
   
   <!-- 清除浮动只能对当前使用clear:both的元素起作用,而闭合浮动则是消除/闭合浮动元素的影响 -->
清除浮动
清除浮动
闭合浮动
闭合浮动

除了上面使用的闭合浮动元素的方案,还有如下:

   .clearfix:before.clearfix:after {
    content"";
    display: table;
   }
   .clearfix:after {
    clear: both;
   }
   .clearfix {
    *zoom1;
   }   

定位造成的高度塌陷的只能通过方式1、2来解决,但是一般不必考虑这种情况。因为一般设定的定位就是我们想要的效果(脱离文档流,完全不会对其他元素造成影响),不会像浮动可能带来不可控的影响。

2)解决 margin 塌陷

  1. 父子盒子元素 margin-top / margin-bottom 重叠(塌陷),即当给紧贴父元素内容区域上边界子元素margin-top(设置父子元素之间的垂直距离)时,父元素也跟着向下移动,相当于给给子元素设置 margin-top 就等于给父元素设置 margin-topmargin-bottom 也如此。解决如下:
   <style>
         /* 解决margin-top/margin-botom塌陷问题:
           1. 给父元素设置上/下边框。
           2. 给父元素设置上/下内边距
           3. 给父元素开启BFC,例如display: flow-root;
       */

         .container {
           background-color: chartreuse;
           width100px;
           height100px;
           /* border-top: 1px solid white; */
           /* padding-top: 1px; */
           /* display: flow-root; */
         }
   
         .child {
           background-color: red;
           width30px;
           height30px;
           margin-top30px;
         }
   
</style>
   <body>
       <div class="container">
         <div class="child"></div>
       </div>
   </body>
父亲元素margin-top塌陷
父亲元素margin-top塌陷
父元素margin-top塌陷解决
父元素margin-top塌陷解决
  1. 兄弟盒子元素塌陷,即垂直方向上相邻的兄弟元素,处于上方的元素设置margin-bottom,处于下方的元素设置margin-top时,两者距离取margin-bottom和margin-top中的最大值,而不是它们的和。解决如下:
   <style>
         /* 解决兄弟元素塌陷问题:
           1.只使用一个调整垂直方向相邻兄弟元素的间距,即设置两个垂直方向的间距,要么让上方元素设置margin-bottom,要么让下方元素设置margin-top。(推荐方式,比较简单就不演示了)
           2.让其中一个元素外套一个父元素,给父元素开启BFC,解决塌陷。(不推荐,改变了文档结构)
       */

         .container {
           display: flow-root;
         }
         .child1 {
           background-color: red;
           width100px;
           height100px;
           margin-bottom30px;
         }
         .child2 {
           background-color: blueviolet;
           width100px;
           height100px;
           margin-top20px;
         }
   
</style>
   <body>
       <div class="child1"></div>
       <div class="container">
         <div class="child2"></div>
       </div>
   </body>
兄弟元素margin塌陷
兄弟元素margin塌陷
兄弟元素margin塌陷解决
兄弟元素margin塌陷解决

参考文献

  • http://nicolasgallagher.com/micro-clearfix-hack/
  • http://t.hk.uy/swG
  • https://blog.csdn.net/qq_26780317/article/details/80764306
  • 《精通CSS-高级Web标准解决方案》第三版

pmcee

2021/06/09  阅读:78  主题:橙心

作者介绍

pmcee