# 圣杯布局

要求:三列布局;中间宽度自适应,两边内容定宽。

好处:重要的内容放在文档流前面可以优先渲染

原理:利用相对定位、浮动、负边距布局,而不添加额外标签

实现方式:

main 部分首先要放在 container 的最前部分。然后是 left,right

1.将三者都 float:left , 再加上一个 position:relative (因为相对定位后面会用到)

2.main 部分 width:100%占满

3.此时 main 占满了,所以要把 left 拉到最左边,使用 margin-left:-100%

4.这时 left 拉回来了,但会覆盖 main 内容的左端,要把 main 内容拉出来,所以在外围 container 加上 padding:0 220px 0 200px

5.main 内容拉回来了,right 也跟着过来了,所以要还原,就对 left 使用相对定位 left:-200px 同理,right 也要相对定位还原 right:-220px

6.到这里大概就自适应好了。如果想 container 高度保持一致可以给 left main right 都加上 min-height:130px

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>实现三栏水平布局之圣杯布局</title>
    <style type="text/css">
      /*基本样式*/
      .left,
      .right,
      .main {
        min-height: 300px;
      }
      .left {
        width: 200px;
        background-color: thistle;
      }
      .main {
        background-color: #999;
      }
      .right {
        width: 300px;
        background-color: violet;
      }
      /* 圣杯布局关键代码 */
      .left,
      .main,
      .right {
        float: left;
        position: relative;
      }
      .main {
        width: 100%;
      }
      .container {
        padding-left: 200px;
        padding-right: 300px;
      }
      .left {
        margin-left: -100%;
        left: -200px;
      }
      .right {
        margin-left: -300px;
        right: -300px;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <div class="main">main</div>
      <div class="left">left</div>
      <div class="right">right</div>
    </div>
  </body>
</html>

# 圣杯布局的实现原理?

  • 要求:三列布局;中间主体内容前置,且宽度自适应;两边内容定宽

    • 好处:重要的内容放在文档流前面可以优先渲染
    • 原理:利用相对定位、浮动、负边距布局,而不添加额外标签
.container {
  padding-left: 150px;
  padding-right: 190px;
}
.main {
  float: left;
  width: 100%;
}
.left {
  float: left;
  width: 190px;
  margin-left: -100%;
  position: relative;
  left: -150px;
}
.right {
  float: left;
  width: 190px;
  margin-left: -190px;
  position: relative;
  right: -190px;
}

# 使用 flex 实现三栏布局,两边固定,中间自适应

这就是圣杯布局,也叫双飞翼布局

  1. 把 center 放在最前面,优先渲染
  2. 相对定位 relative 也是可以设置 left,right 等值的
  3. margin 负值的了解和使用
  4. float 真的不建议使用

现在的 flex/grid 很轻松就能实现,甚至绝对定位也是很容易实现也更容易理解。

作用:圣杯布局和双飞翼布局解决的问题是一样的,就是两边顶宽,中间自适应的三栏布局,中间栏要在放在文档流前面以优先渲染。    区别:圣杯布局,为了中间 div 内容不被遮挡,将中间 div 设置了左右 padding-left 和 padding-right 后,将左右两个 div 用相对布局 position: relative 并分别配合 right 和 left 属性,以便左右两栏 div 移动后不遮挡中间 div。双飞翼布局,为了中间 div 内容不被遮挡,直接在中间 div 内部创建子 div 用于放置内容,在该子 div 里用 margin-left 和 margin-right 为左右两栏 div 留出位置。

圣杯布局代码:

<body>
  <div id="hd">header</div>
  <div id="bd">
    <div id="middle">middle</div>
    <div id="left">left</div>
    <div id="right">right</div>
  </div>
  <div id="footer">footer</div>
</body>

<style>
  #hd {
    height: 50px;
    background: #666;
    text-align: center;
  }
  #bd {
    /*左右栏通过添加负的margin放到正确的位置了,此段代码是为了摆正中间栏的位置*/
    padding: 0 200px 0 180px;
    height: 100px;
  }
  #middle {
    float: left;
    width: 100%; /*左栏上去到第一行*/
    height: 100px;
    background: blue;
  }
  #left {
    float: left;
    width: 180px;
    height: 100px;
    margin-left: -100%;
    background: #0c9;
    /*中间栏的位置摆正之后,左栏的位置也相应右移,通过相对定位的left恢复到正确位置*/
    position: relative;
    left: -180px;
  }
  #right {
    float: left;
    width: 200px;
    height: 100px;
    margin-left: -200px;
    background: #0c9;
    /*中间栏的位置摆正之后,右栏的位置也相应左移,通过相对定位的right恢复到正确位置*/
    position: relative;
    right: -200px;
  }
  #footer {
    height: 50px;
    background: #666;
    text-align: center;
  }
</style>

双飞翼布局代码:

<body>
  <div id="hd">header</div>
  <div id="middle">
    <div id="inside">middle</div>
  </div>
  <div id="left">left</div>
  <div id="right">right</div>
  <div id="footer">footer</div>
</body>

<style>
  #hd {
    height: 50px;
    background: #666;
    text-align: center;
  }
  #middle {
    float: left;
    width: 100%; /*左栏上去到第一行*/
    height: 100px;
    background: blue;
  }
  #left {
    float: left;
    width: 180px;
    height: 100px;
    margin-left: -100%;
    background: #0c9;
  }
  #right {
    float: left;
    width: 200px;
    height: 100px;
    margin-left: -200px;
    background: #0c9;
  }

  /*给内部div添加margin,把内容放到中间栏,其实整个背景还是100%*/
  #inside {
    margin: 0 200px 0 180px;
    height: 100px;
  }
  #footer {
    clear: both; /*记得清楚浮动*/
    height: 50px;
    background: #666;
    text-align: center;
  }
</style>

# flex 布局

<head>
  <style>
    .container {
      border: 1px solid black;
      width: 100vw;
      height: 100vh;

      display: flex;
      flex-direction: row;
      justify-content: space-between;
    }

    .item {
      border: 1px solid red;
      height: 100%;
    }

    .left {
      width: 100px;
    }

    .right {
      flex: 1;
    }
  </style>
</head>

<body class="container">
  <div class="item left">100px宽</div>
  <div class="item right">自适应</div>
</body>

非 flex 布局方式

<html>
  <head>
    <meta charset="utf-8" />
    <title>test.html</title>
    <style>
      .container {
        border: 1px solid black;
        width: 100vw;
        height: 100vh;
      }

      .item {
        border: 1px solid red;
        height: 100%;
      }

      .left {
        float: left;
        width: 100px;
      }

      .right {
        margin: 0 0 0 100px;
      }
    </style>
  </head>

  <body class="container">
    <div class="item left">100px宽</div>
    <div class="item right">自适应</div>
  </body>
</html>