# 一个高度自适应的 div,里面有两个 div,一个高度 100px,希望另一个填满剩下的高度

  • 方案 1: .sub { height: calc(100%-100px); }
  • 方案 2: .container { position:relative; } .sub { position: absolute; top: 100px; bottom: 0; }
  • 方案 3: .container { display:flex; flex-direction:column; } .sub { flex:1; }

# 自适应布局

问题:假设高度默认100px ,请写出三栏布局,其中左栏、右栏各为300px,中间自适应。

  • 方法 1:浮动
  • 方法 2:绝对定位
  • 方法 3:flex box。移动开发里经常用到。
  • 方法 4:表格布局table。虽然已经淘汰了,但也应该了解。
  • 方法 5:网格布局 grid

# 方法 1、浮动:

左侧设置左浮动,右侧设置右浮动即可,中间会自动地自适应。TODO: 中间应该也需要浮动吧 ?

# 方法 2、绝对定位:

左侧设置为绝对定位, left:0px。右侧设置为绝对定位, right:0px。中间设置为绝对定位,leftright 都为300px,即可。中间的宽度会自适应。

使用article标签作为容器,包裹左、中、右三个部分。

方法 1 和方法 2 的代码如下:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Document</title>
    <style>
      html * {
        padding: 0px;
        margin: 0px;
      }

      .layout {
        margin-bottom: 150px;
      }

      .layout article div {
        /*注意,这里是设置每个小块儿的高度为100px,而不是设置大容器的高度。大容器的高度要符合响应式*/
        height: 100px;
      }

      /* 方法一 start */

      .layout.float .left {
        float: left;
        width: 300px;
        background: red;
      }

      .layout.float .right {
        float: right;
        width: 300px;
        background: blue;
      }

      .layout.float .center {
        background: green;
      }

      /* 方法一 end */

      /* 方法二 start */
      .layout.absolute .left-center-right {
        position: relative;
      }

      .layout.absolute .left {
        position: absolute;
        left: 0;
        width: 300px;
        background: red;
      }

      /* 【重要】中间的区域,左侧定位300px,右侧定位为300px,即可完成。宽度会自使用 */
      .layout.absolute .center {
        position: absolute;
        left: 300px;
        right: 300px;
        background: green;
      }

      .layout.absolute .right {
        position: absolute;
        right: 0;
        width: 300px;
        background: blue;
      }

      /* 方法二 end */
    </style>
  </head>

  <body>
    <!-- 方法一:浮动 start -->
    <!-- 输入 section.layout.float,即可生成  -->
    <section class="layout float">
      <!-- 用  article 标签包裹左、中、右三个部分 -->
      <article class="left-right-center">
        <!-- 输入 div.left+div.right+div.center,即可生成 -->
        <div class="left">
          我是 left
        </div>
        <div class="right">
          我是 right
        </div>
        <div class="center">
          浮动解决方案 我是 center
        </div>
      </article>
    </section>
    <!-- 方法一:浮动 end -->

    <section class="layout absolute">
      <article class="left-center-right">
        <div class="left">
          我是 left
        </div>
        <div class="right">
          我是 right
        </div>
        <div class="center">
          <h1>绝对定位解决方案</h1>
          我是 center
        </div>
      </article>
    </section>
  </body>
</html>

效果如下:

# 方法 3、flex box 布局

将左中右所在的容器设置为display: flex,设置两侧的宽度后,然后让中间的flex = 1,即可。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Document</title>
    <style>
      html * {
        padding: 0;
        margin: 0;
      }

      .layout article div {
        height: 100px;
      }

      .left-center-right {
        display: flex;
      }

      .layout.flex .left {
        width: 300px;
        background: red;
      }

      .layout.flex .center {
        flex: 1;
        background: green;
      }

      .layout.flex .right {
        width: 300px;
        background: blue;
      }
    </style>
  </head>

  <body>
    <section class="layout flex">
      <article class="left-center-right-">
        <div class="left">
          我是 left
        </div>
        <div class="center">
          <h1>flex布局解决方案</h1>
          我是 center
        </div>
        <div class="right">
          我是 right
        </div>
      </article>
    </section>
  </body>
</html>

效果如下:

# 方法 4、表格布局 table

设置整个容器的宽度为100%,设置三个部分均为表格,然后左边的单元格为 300px,右边的单元格为 300px,即可。中间的单元格会自适应。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Document</title>
    <style>
      html * {
        padding: 0;
        margin: 0;
      }

      .layout.table div {
        height: 100px;
      }

      /* 重要:设置容器为表格布局,宽度为100% */
      .layout.table .left-center-right {
        width: 100%;
        display: table;
        height: 100px;
      }

      .layout.table .left-center-right div {
        display: table-cell; /* 重要:设置三个模块为表格里的单元*/
      }

      .layout.table .left {
        width: 300px;
        background: red;
      }

      .layout.table .center {
        background: green;
      }

      .layout.table .right {
        width: 300px;
        background: blue;
      }
    </style>
  </head>

  <body>
    <section class="layout table">
      <article class="left-center-right">
        <div class="left">
          我是 left
        </div>
        <div class="center">
          <h1>表格布局解决方案</h1>
          我是 center
        </div>
        <div class="right">
          我是 right
        </div>
      </article>
    </section>
  </body>
</html>

# 方法 5、网格布局 grid

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Document</title>
    <style>
      html * {
        padding: 0;
        margin: 0;
      }

      /* 重要:设置容器为网格布局,宽度为100% */
      .layout.grid .left-center-right {
        display: grid;
        width: 100%;
        grid-template-rows: 100px;
        grid-template-columns: 300px auto 300px; /* 重要:设置网格为三列,并设置每列的宽度。即可。*/
      }

      .layout.grid .left {
        background: red;
      }

      .layout.grid .center {
        background: green;
      }

      .layout.grid .right {
        background: blue;
      }
    </style>
  </head>

  <body>
    <section class="layout grid">
      <article class="left-center-right">
        <div class="left">
          我是 left
        </div>
        <div class="center">
          <h1>网格布局解决方案</h1>
          我是 center
        </div>
        <div class="right">
          我是 right
        </div>
      </article>
    </section>
  </body>
</html>

效果:

# 延伸:五种方法的对比

五种方法的优缺点

  • 考虑中间模块的高度问题
  • 兼容性问题:实际开发中,哪个最实用?

方法 1:浮动:

  • 优点:兼容性好。
  • 缺点:浮动会脱离标准文档流,因此要清除浮动。我们解决好这个问题即可。

方法:2:绝对定位

  • 优点:快捷。
  • 缺点:导致子元素也脱离了标准文档流,可实用性差。

方法 3:flex 布局(CSS3 中出现的)

  • 优点:解决上面两个方法的不足,flex 布局比较完美。移动端基本用 flex 布局。

方法 4:表格布局

  • 优点:表格布局在很多场景中很实用,兼容性非常好。因为 IE8 不支持 flex,此时可以尝试表格布局
  • 缺点:因为三个部分都当成了单元格来对待,此时,如果中间的部分变高了,其会部分也会被迫调整高度。但是,在很多场景下,我们并不需要两侧的高度增高。

什么时候用 flex布局 or 表格布局,看具体的场景。二者没有绝对的优势,也没有绝对的不足。

方法 5:网格布局

  • CSS3 中引入的布局,很好用。代码量简化了很多。

PS:面试提到网格布局,说明我们对新技术是有追求的。

# 延伸:如果题目中去掉高度已知

问题:题目中,如果去掉高度已知,我们往中间的模块里塞很多内容,让中间的模块撑开。会发生什么变化?哪个布局就不能用了?

分析:其实可以这样理解,我们回去看上面的动画效果,当中间的模块变得很挤时,会发生什么效果?就是我们想要的答案。

答案是:flex 布局和表格布局可以通用,其他三个布局都不能用了。

# 布局

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>布局</title>
    <style>
      /* 设置容器 */
      .layout {
        width: 100%;
        display: grid;
        /* 行 */
        grid-template-rows: 100px;
        /* 列 */
        grid-template-columns: 300px auto 300px;
      }

      /* 设置元素 */
      .layout .left {
        background-color: red;
      }

      .layout .right {
        background-color: blue;
      }

      .layout .center {
        background-color: yellow;
      }
    </style>
  </head>

  <body>
    <section class="layout">
      <div class="left"></div>
      <div class="center">中间内容</div>
      <div class="right"></div>
    </section>
  </body>
</html>