谈谈三栏布局的几种方式

三栏式布局是几种常见的布局方式之一,而且实现三栏布局的方式也是有很多,但是大部分的方法都存在这样那样的问题。

绝对定位法(不推荐)

方法简介

使用绝对定位和相对定位来构建三栏式布局,即给外层父div设置相对定位,内层的左右两栏设置绝对定位。中间栏可以使用margin来设置。(三栏元素的位置不会影响布局效果)

但是,使用position来布局会有很大的局限性。因为绝对定位之后,左右两个设置绝对定位的div会脱离文档流,所以父元素的高度有可能会比这两个子元素的高度要小,也就是所谓的高度坍塌。所以为了避免产生这样的bug,可以设置父元素的min-height属性。

相对定位和绝对定位的详细描述可以参考这个:CSS 相对|绝对(relative/absolute)定位系列

demo - 演示
  • HTML

    1
    2
    3
    4
    5
    <div class="container">
    <div class="left">left</div>
    <div class="mid">mid</div>
    <div class="right">right</div>
    </div>
  • CSS

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    .container {
    margin: 20px auto;
    padding: 20px;
    min-width: 600px;
    min-height: 400px;
    background: #ccc;
    /*设置外部父div定位,使得子div的绝对定位是相对于此div*/
    position: relative;
    }
    .left {
    width: 200px;
    height: 300px;
    position: absolute;
    top: 20px;
    left: 20px;
    background: #abc212;
    }
    .right {
    width: 160px;
    height: 200px;
    position: absolute;
    top: 20px;
    right: 20px;
    background: #212bbc;
    }
    .mid {
    margin: 0 180px 0 220px;
    background: #b2bcbb;
    }

浮动定位法

方法简介

左元素左浮动,右元素右浮动,中间元素使用margin来设置位置。(中间div要放在最后)

浮动定位的问题比较常见,解决方法也是多种多样。问题就是父元素可能没有被撑开,也就是说父元素不能使用子元素的高度,可能依旧是0。除了给父元素添加clearfix之外,还有很多其他的方法来清除浮动,这些方法也是各有优劣。

那么为什么中间的div必须放在最后呢?

假如某个div元素A是浮动的,如果A元素上一个元素也是浮动的,那么A元素会跟随在上一个元素的后边(如果一行放不下这两个元素,那么A元素会被挤到下一行);如果A元素上一个元素是标准流中的元素,那么A的相对垂直位置不会改变,也就是说A的顶部总是和上一个元素的底部对齐。

如果中间的div放在左div和右div之间,那么右div向右浮动之后,其位置总是在中间div之下,不能并列,所以中间的div必须放在最后。

对于CSS的清除浮动(clear),一定要牢记:这个规则只能影响使用清除的元素本身,不能影响其他元素。

CSS的浮动的详细解释可以戳这里:CSS浮动

关于清除浮动方法的详细说明可以看这个:What methods of ‘clearfix’ can I use?

demo代码 - 演示
  • HTML

    1
    2
    3
    4
    5
    <div class="container clearfix">
    <div class="left">left</div>
    <div class="right">right</div>
    <div class="mid">mid</div>
    </div>
  • CSS

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    .container {
    padding: 10px;
    background: #ccc;
    }
    /*清除浮动*/
    .clearfix {
    zoom: 1;
    }
    .clearfix:after{
    display: block;
    clear: both;
    height: 0;
    content: '.';
    }
    .left, .mid, .right {
    height: 200px;
    line-height: 200px;
    text-align: center;
    background: #bc2231;
    }
    .left {
    float: left;
    width: 200px;
    }
    .mid {
    margin: 0 220px;
    }
    .right {
    float: right;
    width: 200px;
    }

margin负值法

方法简介

将三列都浮动(本文用的向左浮动),然后改变浮动的位置来实现三栏式。把中间的div放在最前面,同时使用双层div,外层div宽度100%显示,并向左浮动。内层div为真正的主题内容,设置内层div的margin留出左右空间,并且将外层的div的border设置成none。左div和右div都设置负margin值来进行定位,左栏设置向左浮动,设置margin-left成100%,右div左浮,margin-left值也是负值,大小为其本身的宽度(注意border的宽度对本身宽度的影响)。

这个方法需要注意盒模型的宽度包含了border、padding和content,所以在设置margin负值时需要注意大小。

demo代码 - 演示
  • HTML

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <div class="container">
    <div class="mid">
    <div class="content">
    mid
    </div>
    </div>
    <div class="left">left</div>
    <div class="right">right</div>
    </div>
  • CSS

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    div {
    border: 1px solid #000;
    }
    .container {
    margin: 20px;
    padding: 20px;
    min-width: 760px;
    background: #ccc;
    overflow: hidden;
    }
    .left, .mid, .right {
    float: left;
    }
    .mid {
    width: 100%;
    min-width: 300px;
    border: none;
    }
    .content {
    margin: 0 150px 0 220px;
    min-width: 300px;
    padding: 20px;
    }
    .left {
    width: 200px;
    margin-left: -100%;
    }
    .right {
    width: 130px;
    margin-left: -132px;
    }

flex弹性布局

方法简介

使用flexbox来进行三栏式布局其实很简单,只需要左右定宽之后,指定中间div分配全部的剩余空间就可以获得自适应的宽度。

使用flex来布局会产生高度自适应的问题,因为flex分配完剩余空间之后,默认高度会是外层div的高度,比如中间的div撑开高度之后,两边的div也会随着外部div高度的变化而变化,为了解决这个问题,可以设置双层div。

demo代码 - 演示
  • HTML

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    <div class="container">
    <div class="left">
    <div>
    left
    </div>
    </div>
    <div class="mid">
    <div>
    mid
    </div>
    </div>
    <div class="right">
    <div>
    right
    </div>
    </div>
    </div>
  • CSS

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    .container, .container>div>div {
    border: 1px solid #000;
    box-sizing: border-box;
    }
    .container {
    display: flex;
    flex-flow: row;
    min-width: 600px;
    }
    .left,.mid,.right {
    border: none;
    margin: 15px;
    text-align: center;
    }
    .mid {
    flex: 1 auto;
    }
    .left div{
    width: 150px;
    padding: 15px;
    background: #bcc;
    }
    .mid div {
    padding: 15px;
    background: #bcc;
    }
    .right div {
    width: 150px;
    padding: 15px;
    background: #bcc;
    }

总结

使用CSS实现三栏式布局有很多方式(本文有遗漏),最为常用的应该是float,因为float浮动的清除其实很方便,一个clearfix就可以解决问题。

选择什么方式来进行布局其实只要还是看自己对于各种布局方式的优缺点的理解,以及对于布局方式的掌握。

多掌握几种布局方式可以多几种选择,何乐而不为。