三栏布局

Author Avatar
Stein Lee 3月 14, 2017

前言

所谓三栏布局,即使指两边定宽,中间宽度自使用的布局方式,在过去,一直是一个麻烦的问题,
为了解决这个问题,有各种奇技淫巧,最出名的非圣杯布局和双飞翼布局莫属了,但是自CSS3发展以来,
特别是flexbox布局的支持度越来越好,这个问题也越来越淡化了

正文

  1. 浮动布局

    HTML如下:

    ```html
    <div class="left">Left</div>
    <div class="right">Right</div>
    <div class="main">Main</div>
    ```
    

    CSS如下:

     ```css
    body, html {
          height: 100%;
          padding: 0;
          margin: 0;
        }
        .left{
          background: red;
          width:100px;
          float: left;
          height:100%;
        }
        .main{
          background:blue;
          height:100%;
          margin-left:100px;
          margin-right:200px;
        }
        .right{
          background:red;
          width:200px;
          float: right;
          height:100%;
        }
        ```
    

    浮动布局代码比较简洁,同时也易于理解,但是浮动往往会带来塌陷等问题,而且浮动渲染计算量
    较大,在移动端性能表现较差。另一个需要注意的是,main即中间部分需要放在最后,如果是left-main-right的方式
    纳闷main部分将会占满剩余空间,right也就被挤到下一行了,相反,如果我们设置了right和left,在设置main
    main部分将会流入left和right的下面,从而达到我们的目的

  2. 绝对定位

    HTML如下:

    ```html
    <div class="left">left</div>
    <div class="main">main</div>
    <div class="right">right</div>
    ```
    

    CSS如下:

        ```css
       body, html {
          height: 100%;
          padding: 0;
          margin: 0;
        }
    
        .left, .right {
          position: absolute;
          top: 0;
          background: red;
          height: 100%;
        }
    
        .left {
          left: 0;
          width: 100px;
        }
    
        .right {
          right: 0;
          width: 200px;
        }
    
        .main {
          margin-left: 100px;
          margin-right: 200px;
          height: 100%;
          background: blue;
        }
        ```
    

    该方法有个明显的缺点,就是如果中间栏含有最小宽度限制,或是含有宽度的内部元素,当浏览器宽度小到一定程度,会发生层重叠的情况

  3. 圣杯布局

    圣杯布局巧妙的利用负margin来使元素上移,再结合相对定位,移到外层容器的padding位置,从而达到目标

    HTML如下:

    ```html
    <div class="main">main</div>
    <div class="left">left</div>
    <div class="right">right</div>
    ```
    

    CSS如下:

     ```css
    body, html {
          height: 100%;
          padding: 0;
          margin: 0;
        }
        body{
          padding-left:100px;
          padding-right:200px;
        }
        .left{
          background: red;
          width:100px;
          float: left;
          margin-left:-100%;/*-100%:1、导致left超出body内容(此时body内容宽度只有100%-200-100)移到上层2:margin是根据父元素的宽度的,所以-100%就到上层body内容的最前*/
          position: relative;
          left:-100px;/*-100px为了超出body内容左边,到达视窗最左*/
          height:100%;
        }
        .main{
          background: blue;
          width:100%;
          height:100%;
          float: left;
        }
        .right{
          background:red;
          width:200px;
          height:100%;
          float: left;
          margin-left:-200px;/*-200px为了超出body内容到达上一层body内容最后*/
          position: relative;
          right:-200px;/*-200px是为了向右偏移回到视窗最右*/
        }
        .container{
          width:500px;
          height:200px;
        }
        ```
    

    问题:如果外层内容盒宽度过小,不足以容纳.left的宽度,那么.left依然会被保留在下层

  4. 双飞翼布局

    双飞翼布局与圣杯布局原理类似,只不过是取消了外层的padding,从而使内容盒等于padding-box从而避免了.left上移后需要设置left值移动到padding

    HTML如下:

    ```html
    <div class="main">
      <div class="inner">
        main
      </div>
    </div>
    <div class="left">
      left
    </div>
    <div class="right">
      right
    </div>
    ```
    

    CSS如下:

       ```css
      body, html {
           height: 100%;
           padding: 0;
           margin: 0;
         }
         body{
           /*padding-left:100px;*/
           /*padding-right:200px;*/
         }
         .left{
           background: red;
           width:100px;
           float: left;
           margin-left:-100%;/*-100% 1:是为了超出body内容(此时body内容为100%)最左 2:到达body上层内容最左也就是视窗最左
           /*position: relative;*/
           /*left:-100px;*/
           height:100%;
         }
         .main{
           background: blue;
           width:100%;
           height:100%;
           float: left;
         }
         .right{
           background:red;
           width:200px;
           height:100%;
           float: left;
           margin-left:-200px;/*-200px 1:是为了超出body内容(此时body内容为100%)最左 2:到达body上层内容最右也就是视窗最右
           /*position: relative;*/
           /*right:-200px;*/
         }
         .inner{
           margin-left:100px;
           margin-right:200px;
         }
         ```
    

    与圣杯布局不同的地方已用注释指出,而双飞翼问题与圣杯一样

  5. flexbox布局

    flexbox布局可谓是最为理想的解决方案了,一方面,代码简洁易懂,另一方面,当宽度太小时,也可以通过伸缩,避免重叠

    HTML如下:

    ```html
    <div class="main">main</div>
    <div class="left">left</div>
    <div class="right">right</div>
    ```
    

    CSS如下:

       ```css
       body,html{
          height:100%;
          padding: 0;
          margin:0;
        }
        body{
          display: flex;
          flex-flow:row nowrap;
        }
        .left{
          background: red;
          width:100px;
          height:100%;
          order:0;
        }
        .main{
          background-color: blue;
          flex:1;
          height:100%;
          order:1;
        }
        .right{
          background: red;
          width:200px;
          height:100%;
          order:2;
        }
        ```