如何实现两栏布局,右侧自适应?三栏布局中间自适应呢?

2,331 阅读4分钟

前言

在日常布局中,无论是两栏布局还是三栏布局,使用的频率都非常高,而且在面试中,被问到的几率还是挺大的。

两栏布局

两栏布局想要的效果就是将页面分割成左右宽度不等的两列,宽度较小的列设置为固定宽度,剩余宽度由另一列撑满

比如我们常见的Element文档用的就是两栏布局,左边侧边栏占少部分内容,蓝色区域为主要内容布局容器

element.png

三栏布局

三栏布局按照左中右的顺序进行排列,通常中间列最宽且会随着屏幕自适应宽度,左右两列次之

比如vant的文档就是三栏布局

vant.png

两栏布局

两栏布局非常常见,实现思路也很简单,一般是左边固定宽度,右边自适应宽度

浮动实现

  • 使用float使左边容器浮动
  • 右边容器使用margin-left撑出宽度做内容显示
  • 父容器添加BFC,让子容器撑起其高度 代码如下
<style>
  .box {
    overflow: hidden; /*添加BFC*/
  }
  .left {
    float: left;
    width: 200px;
    background-color: goldenrod;
    height: 200px;
  }
  .right {
    margin-left: 200px;
    background-color: lightgray;
    height: 200px;
  }
</style>
<div class="box">
  <div class="left">left</div>
  <div class="right">right</div>
</div>

flex弹性布局实现

  • 给父容器添加display:flex
  • 左边容器设置宽度
  • 右边容器flex:1占据剩余宽度 代码如下
<style>
  .box {
    display: flex;
  }
  .left {
    background-color: greenyellow;
    width: 200px;
    height: 200px;
  }
  .right {
    background-color: fuchsia;
    height: 200px;
    flex: 1;
  }
</style>
<div class="box">
   <div class="left">left</div>
   <div class="right">right</div>
 </div>

flex可以说时最简单的方法,代码量少,但是要注意一点,flex容器默认align-items: stretch;,这会导致两个容器会一直等高,如果不想等高可以给父容器设置一个align-items: flex-start;属性

三栏布局

面试中三栏布局被问到的概率会很大,而且大概率会问道圣杯双飞翼布局,三栏布局主要就是要实现左右两边容器宽度固定,中间容器自适应

两边使用 absolute,中间使用 margin

  • 左右两边容器相对父容器定位
  • 左边 top:0; left:0; 右边 top:0;right:0;
  • 中间占满一行,但通过 margin和左右两边留出位置 代码如下:
<style>
    .container {
      height: 200px;
      position: relative;
    }
    /*左右进行绝对定位*/
    .left,
    .right {
      position: absolute;
      height: 100%;
      top: 0;
      background: #ff69b4;
    }
    .left {
      left: 0;
      width: 200px;
    }
    .right {
      right: 0;
      width: 200px;
    }
    /*中间用margin空出左右元素所占的空间*/
    .center {
      height: 100%;
      padding: 0 200px;
      background: #659;
    }
</style>
<div class="container">
  <div class="center">center</div>
  <div class="left">left</div>
  <div class="right">right</div>
</div>

圣杯布局(两边使用 float 和负 margin)

  • 三个元素放在同一个父级元素中,代表中间盒子的元素放在最前面。
  • 父级盒子设置左右padding,三个盒子全部浮动,设置中间盒子宽度100%。
  • 左右盒子设置固定宽度,设置左边盒子左边距-100%同时相对自身定位,右边平移自身宽度,右边盒子设置右边距-自身宽度。
  • 最后设置父级盒子清除浮动,否则父级盒子的高度无法被撑开。
<style>
.container {
    padding: 0 200px;
    overflow: hidden; /*添加BFC清除浮动*/
  }
  .container .column 
  float: left;
  }
  .center {
    background-color: violet;
    width: 100%;
  }
  .left {
    background-color: wheat;
    width: 200px; 
    margin-left: -100%;
    position: relative;
    right: 200px;
  }
  .right {
    background-color: tomato;
    width: 200px;
    margin-right: -200px;
  }
</style>
<div class="container">
  <div class="column center">center</div>
  <div class="column left">left</div>
  <div class="column right">right</div>
</div>

圣杯布局不需要添加dom节点,正常情况下是没有问题的,但是特殊情况下就会暴露此方案的弊端,当center部分的宽小于left部分时就会发生布局混乱。

双飞翼布局(两边使用 absolute,中间使用 margin)

  • 三个盒子对应三个元素,其中中间盒子套了两层,中间盒子内部盒子设置margin
  • 三个盒子全部浮动,设置中间盒子宽度100%。
  • 左右盒子设置固定宽度,设置左边盒子左边距-100%,右边盒子设置右边距-自身宽度。
  • 后设置父级盒子清除浮动,否则父级盒子的高度无法被撑开。 代码如下:
<style>
  .box {
    overflow: hidden;
  }

  .box .column {
    float: left;
  }
  .left {
    background-color: wheat;
    width: 200px;
    margin-left: -100%;
  }
  .container {
    width: 100%;
  }
  .center {
    background-color: salmon;
    margin: 0 200px;
  }
  .right {
    background-color: springgreen;
    width: 200px;
    margin-right: -200px;
    position: relative;
    right: 200px;
  }
</style>
<div class="box">
  <div class="column container">
    <div class="center">center</div>
  </div>
  <div class="column left">left</div>
  <div class="column right">right</div>
</div>

双飞翼布局优点是不会像圣杯布局那样变形,CSS样式代码更简洁,缺点是多加了一层dom节点

使用 display: table 实现

<table> 标签用于展示行列数据,不适合用于布局。但是可以使用 display: table; 来实现布局的效果

  • 先通过 display: table设置为表格,设置 table-layout: fixed 表示列宽自身宽度决定,而不是自动计算。
  • 内层的左中右通过 display: table-cell设置为表格单元。
  • 左右设置固定宽度,中间设置 width: 100% 填充剩下的宽度。 代码如下:
<style>
  .box {
    height: 200px;
    display: table;
    table-layout: fixed;
    width: 100%;
  }
  .left,
  .right,
  .center {
    display: table-cell;
  }
  .left,
  .right {
    width: 200px;
    background: greenyellow;
  }
  .center {
    background: rosybrown;
    width: 100%;
  }
</style>
<div class="box">
  <div class="left">left</div>
  <div class="center">center</div>
  <div class="right">right</div>
</div>

display: grid; 网格布局

  • 将父容器设置成网格布局
  • grid-template-columns: 200px auto 200px; 设置三列网格其中左右分别200px,中间自适应

代码如下:

<style>
  .box {
   display: grid;
   width: 100%;
   grid-template-columns: 200px auto 200px;  
  }
  .left,
  .right,
  .center {
    height: 200px;
  }
  .left {
    background: coral;
  }
  .right {
    width: 200px;
    background: lightblue;
  }
  .center {
    background: firebrick;
  }
</style>
<div class="box">
  <div class="left">left</div>
  <div class="center">center</div>
  <div class="right">right</div>
</div>

display:flex; 弹性布局

  • 将父容器设置为display:flex;
  • 盒内元素两端对齐,将中间容器设置flex:1,填充空白区域。 代码如下:
<style>
  .box {
    display: flex;
    justify-content: space-between;
  }
  .left,
  .right,
  .center {
    height: 200px;
  }
  .left {
    width: 200px;
    background: coral;
  }
  .right {
    width: 200px;
    background: lightblue;
  }
  .center {
    background: khaki;
    flex: 1;
   }
  </style>
  <div class="box">
    <div class="left">left</div>
    <div class="center">center</div>
    <div class="right">right</div>
  </div>