圣杯布局/双飞翼布局/flex/grid等,实现CSS三栏自适应布局的几种方法

news2024/11/27 15:30:13

简介

三栏布局是网页设计中常用的布局,即网页中的内容被分为三块:左侧/中间/右侧。其中两侧部分宽度固定,中间部分宽度自适应的根据浏览器宽度撑满剩余空间。而三栏布局也有很多变形,比如两栏或者N栏布局,上中下三栏布局,嵌套混合布局等等。掌握了三栏布局的原理,这些类似的布局形式也能轻易实现。

这里我们介绍几种实现自适应三栏布局的几种方法,包括使用flex,grid等方法实现,以及经典的圣杯布局/双飞翼布局等。这些布局的实现源码我放到了Github上面进行了开源(工程使用了vue3实现)。布局的页面效果也放到了网站上供参考:

  • CSS-Layout 各类页面布局示例源码
    https://github.com/jzplp/CSS-Layout
  • CSS-Layout 各类页面布局效果查看网站
    https://jzplp.github.io/CSS-Layout

直接设置宽度

直接设置元素宽度,可以说是最简单也最直接的实现方式了。只要保证元素相加的之后正好为100%,即可实现占满整个页面。假设有的元素是按照像素设置宽度,有的是按照比例设置宽度,那么如何使其相加为100%呢?这就要用到calc(),即CSS中动态计算长度值的函数。

calc和float实现左右三栏布局

即使我们设置了元素宽度,且相加为100%。但是由于块级元素依然默认占据一行,因此我们要加入浮动float: left,使其在一行内排列。

<div class="whole-page">
  <div class="left">左侧</div>
  <div class="middle">中间</div>
  <div class="right">右侧</div>
</div>
.whole-page {
  height: 100vh;
  width: 100vw;
}
.left {
  width: 400px;
  background-color: pink;
  height: 100%;
  float: left;
}
.right {
  width: 300px;
  background-color: green;
  height: 100%;
  float: left;
}
.middle {
  width:calc(100% - 700px);
  background-color: yellow;
  height: 100%;
  float: left;
}

在这里插入图片描述

  • 完整实现源码(vue3):
    https://github.com/jzplp/CSS-Layout/blob/main/src/views/flex/ThreeRow.vue
  • 实现效果查看网址:
    https://jzplp.github.io/CSS-Layout/#/flex/ThreeRow

calc实现上下三栏布局

由于在垂直方向,块级元素并不会垂直方向占据一行,因此不需要有浮动或者其他设置,实现更简单。

<div class="whole-page">
  <div class="top">上面</div>
  <div class="middle">中间</div>
  <div class="bottom">下面</div>
</div>
.whole-page {
  height: 100vh;
  width: 100vw;
}
.top {
  height: 300px;
  background-color: pink;
}
.bottom {
  height: 200px;
  background-color: green;
}
.middle {
  height: calc(100% - 500px);
  background-color: yellow;
}

可以看到,就仅仅计算下高度即可。

在这里插入图片描述

  • 完整实现源码(vue3):
    https://github.com/jzplp/CSS-Layout/blob/main/src/views/calc/ThreeColumn.vue
  • 实现效果查看网址:
    https://jzplp.github.io/CSS-Layout/#/calc/ThreeColumn

calc和float实现两栏或N栏布局

如果不希望要左侧栏或者右侧栏,或者希望按照比例进行宽度大小调整,或者想要四栏甚至更多栏组合,使用calc和float也可以轻易实现。这里使用横向分栏来举例,纵向分栏实际上更简单,去掉float即可。

<div class="part-page container">
  <div class="left1">左侧</div>
  <div class="right1">右侧</div>
</div>
<div class="part-page container">
  <div class="left2">左侧</div>
  <div class="right2">右侧</div>
</div>
<div class="part-page container">
  <div class="left3">左侧</div>
  <div class="right3">右侧</div>
</div>
<div class="part-page container">
  <div class="column1">第一栏 width: 30%</div>
  <div class="column2">第二栏 撑开剩余空间 </div>
  <div class="column3">第三栏 width: 200px</div>
  <div class="column4">第四栏 width: 100px</div>
</div>
.part-page {
  height: 80px;
  margin-bottom: 10px;
}
.container {
  .left1 {
    width: 30%;
    height: 100%;
    background-color: pink;
    float: left;
  }
  .right1 {
    width: 70%;
    height: 100%;
    background-color: green;
    float: left;
  }
  .left2 {
    width: calc(100% - 60%);
    height: 100%;
    float: left;
    background-color: pink;
  }
  .right2 {
    width: 60%;
    height: 100%;
    float: left;
    background-color: green;
  }
  .left3 {
    width: 300px;
    height: 100%;
    float: left;
    background-color: pink;
  }
  .right3 {
    width: calc(100% - 300px);
    height: 100%;
    float: left;
    background-color: green;
  }
  .column1 {
    width: 30%;
    height: 100%;
    float: left;
    background-color: pink;
  }
  .column2 {
    width: calc(100% - 30% - 200px - 100px);
    height: 100%;
    float: left;
    background-color: green;
  }
  .column3 {
    height: 100%;
    float: left;
    width: 200px;
    background-color: yellow;
  }
  .column4 {
    height: 100%;
    float: left;
    width: 100px;
    background-color: grey;
  }
}

在这里插入图片描述

这些不同的方案描述:

  1. 左右两栏设置不同的宽度比例。
  2. 宽度比例由calc计算得出。
  3. 左侧设置固定宽度,右侧占满剩余宽度。
  4. 四栏实例,为上面方案的组合。
  • 完整实现源码(vue3):
    https://github.com/jzplp/CSS-Layout/blob/main/src/views/calc/ScaleRow.vue
  • 实现效果查看网址:
    https://jzplp.github.io/CSS-Layout/#/calc/ScaleRow

calc和float实现上下左右三栏嵌套布局

上面我们实现了左右三栏布局和上下三栏布局。在更复杂的页面中,我们需要同时使用左右三栏和上下三栏,此时我们的实现也能很方便的进行组合。这里以上下嵌套左右三栏为例。

<div class="whole-page container">
  <div class="top">上面</div>
  <div class="middle">
    <div class="left">左侧</div>
    <div class="middle-deep">中间</div>
    <div class="right">右侧</div>
  </div>
  <div class="bottom">下面</div>
</div>
.whole-page {
  height: 100vh;
  width: 100vw;
}
.container {
  --top-value: 300px;
  --bottom-value: 200px;
  --left-value: 400px;
  --right-value: 300px;
  .top {
    height: var(--top-value);
    background-color: pink;
  }
  .bottom {
    height: var(--bottom-value);
    background-color: green;
  }
  .middle {
    height: calc(100% - var(--top-value) - var(--bottom-value));
    .left {
      width: 400px;
      background-color: grey;
      height: 100%;
      float: left;
    }
    .right {
      width: 300px;
      background-color: aqua;
      height: 100%;
      float: left;
    }
    .middle-deep {
      width: calc(100% - var(--left-value) - var(--right-value));
      background-color: yellow;
      height: 100%;
      float: left;
    }
  }
}

为了方便查看,我使用了四个css变量来标明上下左右四边的宽度。

在这里插入图片描述

  • 完整实现源码(vue3):
    https://github.com/jzplp/CSS-Layout/blob/main/src/views/calc/MultiRowColumn.vue
  • 实现效果查看网址:
    https://jzplp.github.io/CSS-Layout/#/calc/MultiRowColumn

使用flex实现

使用flex布局,可以简单的实现三栏布局,其中的关键在于flex-grow: 1,即定义元素的放大比例。如果其它的元素flex-grow为0,需要撑开的元素flex-grow设为1,即可以实现自适应。

flex左右三栏布局

<div class="whole-page container">
  <div class="left">左侧</div>
  <div class="middle">中间</div>
  <div class="right">右侧</div>
</div>
.whole-page {
  height: 100vh;
  width: 100vw;
}
.container {
  display: flex;
  .left {
    width: 400px;
    background-color: pink;
  }
  .right {
    width: 300px;
    background-color: green;
  }
  .middle {
    flex:1;
    background-color: yellow;
  }
}

在这里插入图片描述

  • 完整实现源码(vue3):
    https://github.com/jzplp/CSS-Layout/blob/main/src/views/calc/ThreeRow.vue
  • 实现效果查看网址:
    https://jzplp.github.io/CSS-Layout/#/calc/ThreeRow

flex上下三栏布局

上下三栏布局与左右三栏布局基本一模一样,区别就仅仅是多加了一个flex-direction: column

<div class="whole-page container">
  <div class="top">上面</div>
  <div class="middle">中间</div>
  <div class="bottom">下面</div>
</div>
.whole-page {
  height: 100vh;
  width: 100vw;
}
.container {
  display: flex;
  flex-direction: column;
  .top {
    height: 300px;
    background-color: pink;
  }
  .bottom {
    height: 200px;
    background-color: green;
  }
  .middle {
    flex:1;
    background-color: yellow;
  }
}

在这里插入图片描述

  • 完整实现源码(vue3):
    https://github.com/jzplp/CSS-Layout/blob/main/src/views/flex/ThreeColumn.vue
  • 实现效果查看网址:
    https://jzplp.github.io/CSS-Layout/#/flex/ThreeColumn

flex两栏或N栏布局

如果不希望要左侧栏或者右侧栏,或者按照实际内容撑开,或者想要四栏甚至更多栏,那么上面的布局稍微改变下即可实现。下面的代码中给出了多种不同的实现方案:

<div class="part-page container">
  <div class="left1">左侧</div>
  <div class="right1">右侧</div>
</div>
<div class="part-page container">
  <div class="left2">左侧</div>
  <div class="right2">右侧</div>
</div>
<div class="part-page container">
  <div class="left3">左侧</div>
  <div class="right3">右侧</div>
</div>
<div class="part-page container">
  <div class="left4">左侧</div>
  <div class="right4">右侧</div>
</div>
<div class="part-page container">
  <div class="left5">左侧 按实际内容撑开</div>
  <div class="right5">右侧</div>
</div>
<div class="part-page container">
  <div class="left6">左侧</div>
  <div class="right6">右侧 按实际内容撑开</div>
</div>
<div class="part-page container">
  <div class="column1">第一栏 按实际内容撑开</div>
  <div class="column2">第二栏 width: 30% </div>
  <div class="column3">第三栏 flex-grow: 1</div>
  <div class="column4">第四栏 width: 200px</div>
</div>
.part-page {
  height: 80px;
  margin-bottom: 10px;
}
.container {
  display: flex;
  .left1 {
    width: 30%;
    background-color: pink;
  }
  .right1 {
    width: 70%;
    background-color: green;
  }
  .left2 {
    flex-grow: 1;
    background-color: pink;
  }
  .right2 {
    width: 60%;
    background-color: green;
  }
  .left3 {
    flex-grow: 1;
    background-color: pink;
  }
  .right3 {
    flex-grow: 1;
    background-color: green;
  }
  .left4 {
    flex-grow: 1;
    background-color: pink;
  }
  .right4 {
    flex-basis: 40%;
    background-color: green;
  }
  .left5 {
    background-color: pink;
  }
  .right5 {
    flex-grow: 1;
    background-color: green;
  }
  .left6 {
    flex-grow: 1;
    background-color: pink;
  }
  .right6 {
    background-color: green;
  }
  .column1 {
    background-color: pink;
  }
  .column2 {
    width: 30%;
    background-color: green;
  }
  .column3 {
    flex-grow: 1;
    background-color: yellow;
  }
  .column4 {
    width: 200px;
    background-color: aqua;
  }
}

在这里插入图片描述

这些不同的方案描述:

  1. 直接设置宽度比例,相加为100%即可。
  2. 一个设置宽度,另外一个设置flex-grow: 1
  3. 两个都设置flex-grow: 1,即实现左右宽度相等。
  4. 设置flex-basis,与直接设置width效果基本一致。
  5. 左侧不设置宽度,右侧设置flex-grow: 1。即左侧为实际内容宽度,右侧占满剩余宽度。
  6. 右侧为实际内容宽度,作侧占满剩余宽度。
  7. 四栏实例,为上面方案的组合。
  • 完整实现源码(vue3):
    https://github.com/jzplp/CSS-Layout/blob/main/src/views/flex/ScaleRow.vue
  • 实现效果查看网址:
    https://jzplp.github.io/CSS-Layout/#/flex/ScaleRow

flex上下左右三栏嵌套布局

同样的,使用flex也可以对上面的布局进行混合和嵌套。这里依然以上下嵌套左右三栏为例。

<div class="whole-page container">
  <div class="top">上面</div>
  <div class="middle">
    <div class="left">左侧</div>
    <div class="middle-deep">中间</div>
    <div class="right">右侧</div>
  </div>
  <div class="bottom">下面</div>
</div>
.whole-page {
  height: 100vh;
  width: 100vw;
}
.container {
  display: flex;
  flex-direction: column;
  .top {
    height: 300px;
    background-color: pink;
  }
  .bottom {
    height: 200px;
    background-color: green;
  }
  .middle {
    flex-grow: 1;
    display: flex;
    .left {
      width: 400px;
      background-color: grey;
    }
    .right {
      width: 300px;
      background-color: aqua;
    }
    .middle-deep {
      flex-grow: 1;
      background-color: yellow;
    }
  }
}

在这里插入图片描述

  • 完整实现源码(vue3):
    https://github.com/jzplp/CSS-Layout/blob/main/src/views/flex/multiRowColumn.vue
  • 实现效果查看网址:
    https://jzplp.github.io/CSS-Layout/#/flex/MultiRowColumn

使用grid实现

grid是一种强大的网格布局方法,将页面元素划分为一个一个的网格。在实际的布局中,比flex更为强大。三栏布局对grid来说非常轻松,而且还能实现更多复杂的布局方案。

grid左右三栏布局

直接设置grid-template-columns分割即可。需要占据剩余空间的元素元素设置auto或者1fr。

<div class="whole-page container">
  <div class="left">左侧</div>
  <div class="middle">中间</div>
  <div class="right">右侧</div>
</div>
.whole-page {
  height: 100vh;
  width: 100vw;
}
.container {
  display: grid;
  grid-template-columns: 400px auto 300px;
  .left {
    background-color: pink;
  }
  .right {
    background-color: green;
  }
  .middle {
    background-color: yellow;
  }
}

在这里插入图片描述

  • 完整实现源码(vue3):
    https://github.com/jzplp/CSS-Layout/blob/main/src/views/grid/ThreeRow.vue
  • 实现效果查看网址:
    https://jzplp.github.io/CSS-Layout/#/grid/ThreeRow

grid上下三栏布局

上下三栏布局与左右三栏布局基本一模一样,区别就仅仅是grid-template-columns换成了grid-template-rows。

<div class="whole-page container">
  <div class="top">上面</div>
  <div class="middle">中间</div>
  <div class="bottom">下面</div>
</div>
.whole-page {
  height: 100vh;
  width: 100vw;
}
.container {
  display: grid;
  grid-template-rows: 300px auto 200px;
  .top {
    background-color: pink;
  }
  .bottom {
    background-color: green;
  }
  .middle {
    background-color: yellow;
  }
}

在这里插入图片描述

  • 完整实现源码(vue3):
    https://github.com/jzplp/CSS-Layout/blob/main/src/views/grid/ThreeColumn.vue
  • 实现效果查看网址:
    https://jzplp.github.io/CSS-Layout/#/grid/ThreeColumn

grid两栏或N栏布局

grid布局的强大,使其可以有更多两栏甚至N栏布局的方式,这里列举一些。

<div class="part-page container1">
  <div class="left">左侧</div>
  <div class="right">右侧</div>
</div>
<div class="part-page container2">
  <div class="left">左侧</div>
  <div class="right">右侧</div>
</div>
<div class="part-page container3">
  <div class="left">左侧</div>
  <div class="right">右侧</div>
</div>
<div class="part-page container4">
  <div class="left">左侧</div>
  <div class="right">右侧</div>
</div>
<div class="part-page container5">
  <div class="left">左侧</div>
  <div class="right">右侧</div>
</div>
<div class="part-page container6">
  <div class="left">左侧 按实际内容撑开</div>
  <div class="right">右侧</div>
</div>
<div class="part-page container7">
  <div class="column1">第一栏 200px</div>
  <div class="column2">第二栏 30%</div>
  <div class="column3">第三栏 1fr</div>
  <div class="column4">第四栏 auto按实际内容撑开</div>
</div>
.part-page {
  height: 80px;
  margin-bottom: 10px;
}
.left {
  background-color: pink;
}
.right {
  background-color: green;
}
.container1 {
  display: grid;
  grid-template-columns: 30% 70%;
}
.container2 {
  display: grid;
  grid-template-columns: auto 60%;
}
.container3 {
  display: grid;
  grid-template-columns: auto auto;
}
.container4 {
  display: grid;
  grid-template-columns: 200px auto;
}
.container5 {
  display: grid;
  grid-template-columns: 300px 1fr;
}
.container6 {
  display: grid;
  grid-template-columns: auto 1fr;
}
.container7 {
  display: grid;
  grid-template-columns: 200px 30% 1fr auto;
  .column1 {
    background-color: pink;
  }
  .column2 {
    background-color: green;
  }
  .column3 {
    background-color: yellow;
  }
  .column4 {
    background-color: aqua;
  }
}

在这里插入图片描述

这些不同的方案描述:

  1. 设置两栏比例。
  2. 左侧设置比例,右侧撑开剩余空间。
  3. 两个都是auto,均分空间。
  4. 左侧固定宽度,右侧撑开剩余空间。
  5. 左侧固定宽度,右侧使用1fr撑开剩余空间。
  6. 左侧按照实际内容撑开,右侧使用1fr撑开剩余空间。
  7. 四栏实例,为上面方案的组合。

当auto和1fr单独使用时,作用都是撑开剩余空间。但是当同时使用时,1fr的优先级更高,作用依然是撑开剩余空间。但是auto的作用则变成了按照实际包含内容作为宽度(可以看第六个例子)。

  • 完整实现源码(vue3):
    https://github.com/jzplp/CSS-Layout/blob/main/src/views/grid/ScaleRow.vue
  • 实现效果查看网址:
    https://jzplp.github.io/CSS-Layout/#/grid/ScaleRow

grid上下左右三栏嵌套布局

在上面,我们使用了flex对上下三栏和左右三栏布局进行了嵌套。同样的,grid布局也可以做到。

<div class="whole-page container">
  <div class="top">上面</div>
  <div class="middle">
    <div class="left">左侧</div>
    <div class="middle-deep">中间</div>
    <div class="right">右侧</div>
  </div>
  <div class="bottom">下面</div>
</div>
.whole-page {
  height: 100vh;
  width: 100vw;
}
.container {
  display: grid;
  grid-template-rows: 300px auto 200px;
  .top {
    background-color: pink;
  }
  .bottom {
    background-color: green;
  }
  .middle {
    display: grid;
    grid-template-columns: 400px auto 300px;
    .left {
      background-color: grey;
    }
    .right {
      background-color: aqua;
    }
    .middle-deep {
      background-color: yellow;
    }
  }
}

在这里插入图片描述

  • 完整实现源码(vue3):
    https://github.com/jzplp/CSS-Layout/blob/main/src/views/grid/MultiRowColumnNest.vue
  • 实现效果查看网址:
    https://jzplp.github.io/CSS-Layout/#/grid/MultiRowColumnNest

grid上下左右三栏网格布局

grid本身就支持这种网格布局方式,上面对grid进行嵌套有点画蛇添足了。这里我们直接利用网格实现。

<div class="whole-page container">
  <div class="top">上面</div>
  <div class="left">左侧</div>
  <div class="middle-deep">中间</div>
  <div class="right">右侧</div>
  <div class="bottom">下面</div>
</div>
.whole-page {
  height: 100vh;
  width: 100vw;
}
.container {
  display: grid;
  grid-template-rows: 300px auto 200px;
  grid-template-columns: 400px auto 300px;
  .top {
    grid-column-start: 1;
    grid-column-end: 4;
    background-color: pink;
  }
  .bottom {
    grid-column-start: 1;
    grid-column-end: 4;
    background-color: green;
  }
  .left {
    background-color: grey;
  }
  .right {
    background-color: aqua;
  }
  .middle-deep {
    background-color: yellow;
  }
}

在这里插入图片描述

可以看到,利用网格合并,可以直接实现一样的效果。

  • 完整实现源码(vue3):
    https://github.com/jzplp/CSS-Layout/blob/main/src/views/grid/MultiRowColumnGrid.vue
  • 实现效果查看网址:
    https://jzplp.github.io/CSS-Layout/#/grid/MultiRowColumnGrid

圣杯布局

上面的几种布局,在页面DOM结构上,都是先左侧再中间后右侧。虽然这和页面的展示顺序是一致的,但也造成了在页面渲染中,先左侧渲染,再中间渲染。在部分场景下,这种渲染顺序是不行的。

试想一种场景:一个页面的中间是主要内容,左侧和右侧是不重要的内容,甚至是广告。用户在浏览页面时,左侧的广告会先加载然后才是中间的主要内容。这样对于用户的浏览体验太差了。因此,我们要找到一种布局方式,在DOM结构上是中间在前左侧在后,保证页面是中间先渲染;但是在页面展示中却是左侧居左中间居中布局方式。

这种布局方式就是经典的——圣杯布局。圣杯布局来源于2006年的这篇文章:In Search of the Holy Grail

圣杯布局解析

首先是HTML结构,可以看到确实中间在前,左侧在后。为了方便后续引用,我们设置了两个CSS变量,分别代表左侧和右侧的宽度,方便后面引用。三个区域都撑满高度。

<div class="whole-page container">
  <div class="middle">中间</div>
  <div class="left">左侧</div>
  <div class="right">右侧</div>
</div>
<style>
.whole-page {
  height: 100vh;
}
.container {
  --left-value: 400px;
  --right-value: 300px;
  .left {
    height: 100%;
    background-color: pink;
    width: var(--left-value);
  }
  .right {
    height: 100%;
    background-color: green;
    width: var(--right-value);
  }
  .middle {
    height: 100%;
    background-color: yellow;
  }
}
</style>

然后设置容器的padding,左边为左侧的宽度,右边为右侧的宽度。

.container {
  padding: 0 var(--right-value) 0 var(--left-value);
}

此时三个元素各自占一行,都挤在中间区域。此时我们设置下三个区域的浮动,使其脱离文档流,在同一行显示。

.left {
  float: left;
}
.right {
  float: left;
}
.middle {
  float: left;
}

此时我们发现三个区域跑到一行展示了,但是依然按照中间左侧右侧的顺序挤在容器中间位置。这时候我们让左侧区域相对定位,靠左一个宽度值,使其位置正好在容器的左侧。

.left {
  position: relative;
  left: calc(-1 * var(--left-value));
}

但是这样依然很奇怪,运行一下可以看到左侧并不完全靠左,而是空出了一个当前中间区域宽度的位置,而且左侧宽度正好把中间区域的宽度覆盖了。因为在相对定位之前,左侧区域的位置就并不是靠着容器的左侧,因此设置往左一个相对的左侧宽度也不能使其到达正确的位置。

此时我们可以设置中间区域的宽度为占满父元素宽度,这样中间和左侧区域的横向位置就正确了。

.middle {
  width: 100%;
}

这时我们会发现:虽然左侧区域的横向位置正确了,但左侧区域被挤到了第二行。这时因为中间区域占满了全部宽度,左侧区域没有位置了。这时候我们需要让这几个区域都在同一行。

我们使用负magrin来实现。在设置了浮动且移动到父元素边框以外时,就会向上浮动。

.left {
  margin-left: -100%;
}

我们让左侧区域的margin-left为100%,实际上也就是容器的宽度,那么左侧区域会上浮到第一行,而且完全在容器的左侧。

同样的,我们对右侧区域也使用负magrin。值为右侧自己的宽度,同样右侧区域也能上浮到第一行,且完全在容器的右侧。

.right {
  margin-right: calc(-1 * var(--right-value));
}

到这里,我们已经做到了左右三栏布局的效果,且中间区域先渲染。

在这里插入图片描述

圣杯布局源码

<div class="whole-page container">
  <div class="middle">中间</div>
  <div class="left">左侧</div>
  <div class="right">右侧</div>
</div>
.whole-page {
  height: 100vh;
}
.container {
  --left-value: 400px;
  --right-value: 300px;
  padding: 0 var(--right-value) 0 var(--left-value);
  .left {
    float: left;
    position: relative;
    left: calc(-1 * var(--left-value));
    width: var(--left-value);
    background-color: pink;
    height: 100%;
    margin-left: -100%;
  }
  .right {
    float: left;
    width: var(--right-value);
    background-color: green;
    height: 100%;
    margin-right: calc(-1 * var(--right-value));
  }
  .middle {
    float: left;
    background-color: yellow;
    height: 100%;
    width: 100%;
  }
}
  • 完整实现源码(vue3):
    https://github.com/jzplp/CSS-Layout/blob/main/src/views/holyGrail/HolyGrail.vue
  • 实现效果查看网址:
    https://jzplp.github.io/CSS-Layout/#/holyGrail/HolyGrail

圣杯布局对于中间区域的位置虽然可以自适应,但实际上是有最小宽度要求的,即不能小于左侧区域的宽度。如果小于,则左侧和右侧区域会都跑到第二行了。

上下三栏嵌套圣杯布局

圣杯布局的外面同样可以嵌套其他的布局方式,比如上下左右三栏嵌套布局。上下三栏一般没有加载顺序要求,从上往下加载即可,因此我们使用最简单的计算calc实现。使用其他布局方式也同样可以。

<div class="whole-page container">
  <div class="top">上面</div>
  <div class="middle">
    <div class="middle-deep">中间</div>
    <div class="left">左侧</div>
    <div class="right">右侧</div>
  </div>
  <div class="bottom">下面</div>
</div>
.whole-page {
  height: 100vh;
}
.container {
  --top-value: 300px;
  --bottom-value: 200px;
  --left-value: 400px;
  --right-value: 300px;
  .top {
    height: var(--top-value);
    background-color: pink;
  }
  .bottom {
    height: var(--bottom-value);
    background-color: green;
  }
  .middle {
    height: calc(100% - var(--top-value) - var(--bottom-value));
    padding: 0 var(--right-value) 0 var(--left-value);
    .left {
      float: left;
      position: relative;
      left: calc(-1 * var(--left-value));
      width: var(--left-value);
      background-color: grey;
      height: 100%;
      margin-left: -100%;
    }
    .right {
      float: left;
      width: var(--right-value);
      background-color: aqua;
      height: 100%;
      margin-right: calc(-1 * var(--right-value));
    }
    .middle-deep {
      float: left;
      background-color: yellow;
      height: 100%;
      width: 100%;
    }
  }
}

在这里插入图片描述

  • 完整实现源码(vue3):
    https://github.com/jzplp/CSS-Layout/blob/main/src/views/holyGrail/MultiRowColumn.vue
  • 实现效果查看网址:
    https://jzplp.github.io/CSS-Layout/#/holyGrail/MultiRowColumn

双飞翼布局

双飞翼布局来源于淘宝,是圣杯布局的一种改进。解决了圣杯布局要求中间区域最小宽度的问题。

双飞翼布局解析

首先是HTML结构,与圣杯基本一致,区别就在于中间区域多套了一层。

<template>
  <div class="whole-page container">
    <div class="middle">
      <div class="inner">中间</div>
    </div>
    <div class="left">左侧</div>
    <div class="right">右侧</div>
  </div>
</template>

<style lang="less" scoped>
.whole-page {
  height: 100vh;
}
.container {
  --left-value: 400px;
  --right-value: 300px;
  .left {
    background-color: pink;
    height: 100%;
    width: var(--left-value);
  }
  .right {
    background-color: green;
    height: 100%;
    width: var(--right-value);
  }
  .middle {
    background-color: yellow;
    height: 100%;
  }
}
</style>

然后我们设置中间区域的宽度为撑满父容器宽度,中间区域的内部元素的左右padding设置为左侧和右侧的宽度。

.middle {
  width: 100%;
  .inner {
      padding-left: var(--left-value);
      padding-right: var(--right-value);
      height: 100%;
    }
}

到这里我们已经看出,双飞翼布局是以中间区域作为整个布局空间的,左侧和右侧区域在后面都会盖到中间区域的padding上。这里使用margin也可以。

三个区域都设置浮动,且左测和右侧区域都设置负值margin。这里的用法与圣杯布局一样,让三个区域都在同一行展示,且放置在正确的位置上。

.left {
  float: left;
  margin-left: -100%;
}
.right {
  float: left;
  margin-left: calc(-1 * var(--right-value));
}
.middle {
  float: left;
}

到这里我们的布局就已经完成了。这时候我们改变浏览器的宽度,中间区域也能自适应缩放,且对于中间区域的宽度没有大小要求。

在这里插入图片描述

双飞翼布局源码

<div class="whole-page container">
  <div class="middle">
    <div class="inner">中间</div>
  </div>
  <div class="left">左侧</div>
  <div class="right">右侧</div>
</div>
.whole-page {
  height: 100vh;
}
.container {
  --left-value: 400px;
  --right-value: 300px;
  .left {
    background-color: pink;
    height: 100%;
    width: var(--left-value);
    float: left;
    margin-left: -100%;
  }
  .right {
    background-color: green;
    height: 100%;
    width: var(--right-value);
    float: left;
    margin-left: calc(-1 * var(--right-value));
  }
  .middle {
    background-color: yellow;
    height: 100%;
    width: 100%;
    float: left;
    .inner {
      padding-left: var(--left-value);
      padding-right: var(--right-value);
      height: 100%;
    }
  }
}
  • 完整实现源码(vue3):
    https://github.com/jzplp/CSS-Layout/blob/main/src/views/flyingSwing/FlyingSwing.vue
  • 实现效果查看网址:
    https://jzplp.github.io/CSS-Layout/#/flyingSwing/FlyingSwing

上下三栏嵌套双飞翼布局

同样的,双飞翼布局也可以嵌套使用,这里我们依然使用简单的计算calc实现上下三栏布局,中间嵌套双飞翼布局。

<div class="whole-page container">
  <div class="top">上面</div>
  <div class="middle">
    <div class="middle-deep">
      <div class="inner">中间</div>
    </div>
    <div class="left">左侧</div>
    <div class="right">右侧</div>
  </div>
  <div class="bottom">下面</div>
</div>
.whole-page {
  height: 100vh;
}
.container {
  --top-value: 300px;
  --bottom-value: 200px;
  --left-value: 400px;
  --right-value: 300px;
  .top {
    height: var(--top-value);
    background-color: pink;
  }
  .bottom {
    height: var(--bottom-value);
    background-color: green;
  }
  .middle {
    height: calc(100% - var(--top-value) - var(--bottom-value));
    .left {
      background-color: grey;
      height: 100%;
      width: var(--left-value);
      float: left;
      margin-left: -100%;
    }
    .right {
      background-color: aqua;
      height: 100%;
      width: var(--right-value);
      float: left;
      margin-left: calc(-1 * var(--right-value));
    }
    .middle-deep {
      background-color: yellow;
      float: left;
      height: 100%;
      width: 100%;
      .inner {
        margin-left: var(--left-value);
        margin-right: var(--right-value);
        height: 100%;
      }
    }
  }
}

在这里插入图片描述

  • 完整实现源码(vue3):
    https://github.com/jzplp/CSS-Layout/blob/main/src/views/flyingSwing/MultiRowColumn.vue
  • 实现效果查看网址:
    https://jzplp.github.io/CSS-Layout/#/flyingSwing/MultiRowColumn

总结

通过上面的实现,可以看到实现三栏布局其实有很多种方法,简单的有直接计算calc,flex等,复杂一点的有圣杯和双飞翼。那么我们在遇到三栏布局时,是不是应该直接使用复杂的圣杯和双飞翼,而不使用简单的布局方法呢?

并不是越复杂的实现就越好。圣杯和双飞翼是为了解决希望中间先渲染的问题,所以将中间区域的DOM结构在前,又为了保证布局效果和可嵌套使用而实现的。

如果我们的页面没有广告,不需要考虑左侧和中间区域的加载问题,直接使用简单的flex等布局即可,没必要改变DOM结构。

参考

  • CSS-Layout 各类页面布局示例源码
    https://github.com/jzplp/CSS-Layout
  • CSS-Layout 各类页面布局效果查看网站
    https://jzplp.github.io/CSS-Layout
  • Flex 布局教程:语法篇 阮一峰的网络日志
    https://www.ruanyifeng.com/blog/2015/07/flex-grammar.html
  • Flex 布局教程:实例篇 阮一峰的网络日志
    https://www.ruanyifeng.com/blog/2015/07/flex-examples.html
  • CSS Grid 网格布局教程 阮一峰的网络日志
    https://ruanyifeng.com/blog/2019/03/grid-layout-tutorial.html
  • In Search of the Holy Grail 圣杯布局
    https://alistapart.com/article/holygrail/
  • 面试官:如何实现三栏布局,中间自适应
    https://juejin.cn/post/7276398869734817832
  • css margin负值
    https://www.cnblogs.com/gaoBlog/p/16683325.html
  • 双飞翼布局介绍-始于淘宝UED
    https://www.cnblogs.com/czone/archive/2012/11/30/2795732.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1175352.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【漏洞复现】S2-045 Remote Code Execution(CVE-2017-5638)

感谢互联网提供分享知识与智慧&#xff0c;在法治的社会里&#xff0c;请遵守有关法律法规 文章目录 1.1、漏洞描述1.2、漏洞等级1.3、影响版本1.4、漏洞复现1、基础环境2、漏洞扫描nacs3、漏洞验证 1.5、修复建议 说明内容漏洞编号CVE-2017-5638漏洞名称S2-045 远程代码执行漏…

51单片机-中断

文章目录 前言 前言 #include <reg52.h> #include <intrins.h>sbit key_s2P3^0; sbit flagP3^7;void delay(unsigned int z){unsigned int x,y;for(xz;x>0;x--)for(y114;y>0;y--); }void int_init(){EA1;EX11;IT11;}void main(){int_init();while(1){if (key…

【产品资料】产品经理面试问题(三)

今天和大家免费分享产品经理常见的面试题目&#xff0c;含回答思路分析和回答事例。 【资源下载】 这个资源可以在Axure高保真原型哦小程序里免费下载 打开下方小程序后&#xff0c;搜索产品经理面试题目&#xff0c;获取下载地址 更多原型模板、视频教程、产品文档、定制服…

c++11中的线程库和包装器

c11 1. 线程库1.1 线程库1.2 锁mutex 2. 包装器2.1 funciton2.2 bind 1. 线程库 1.1 线程库 C11中的线程库提供了一种方便的方式来创建和管理线程。其中&#xff0c;std::thread是一个重要的类&#xff0c;它允许我们创建新线程并控制它们的执行。以下是std::thread的一些重要…

磁盘物理结构介绍(磁头,扇区),chs寻址,如何读写,磁盘io消耗时间;线性抽象结构,lba寻址,分区引入

目录 磁盘文件 引入 看待角度 磁盘 介绍 物理结构 俯视图 立体图 磁头 扇区 如何找到一个扇区 -- CHS寻址 如何读写 磁盘io消耗时间 抽象结构 -- 线性 引入 介绍 -- LBA寻址 分区 引入 介绍 磁盘文件 引入 文件分为两种 被打开的文件(主要讨论与进程之间的…

python基础速通

1. 梳理&#xff1a;目前学习了哪几种数据类型&#xff0c; 每一个数据类型定义一个变量&#xff0c;并输出内容以及类型 # 数据类型 # 整型 int_data 1 print(int_data, type(int_data)) # 浮点型 float_data 1.2 print((float_data, type(float_data))) # 复数 complex_da…

计算机毕设 基于大数据的社交平台数据爬虫舆情分析可视化系统

文章目录 0 前言1 课题背景2 实现效果**实现功能****可视化统计****web模块界面展示**3 LDA模型 4 情感分析方法**预处理**特征提取特征选择分类器选择实验 5 部分核心代码6 最后 0 前言 &#x1f525; 这两年开始毕业设计和毕业答辩的要求和难度不断提升&#xff0c;传统的毕…

Monarch Mixer:一种性能比Transformer更强的网络架构

六年前&#xff0c;谷歌团队在arXiv上发表了革命性的论文《Attention is all you need》。作为一种优势的机器学习网络架构&#xff0c;Transformer技术迅速席卷全球。Transformer一直是现代基础模型背后的主力架构&#xff0c;并且在不同的应用程序中取得了令人印象深刻的成功…

[云原生1. ] Docker consul的详细介绍(容器服务的更新与发现)

文章目录 1. 服务注册与发现的概述1.1 cmp问题1.2 解决方法 2. Consul的概述2.1 简介2.2 为什么要使用Consul服务模块2.2 Consul的服务架构2.3 Consul的一些关键特性 3. consul服务部署3.1 前置准备3.2 Consul服务器3.2.1 建立 Consul 服务3.2.2 设置代理&#xff0c;在后台启动…

Linux开发工具的使用(vim、gcc/g++)

文章目录 vimvim基本概念vim的常用三种模式vim三种模式的相互转换vim命令模式下的命令集移动光标删除文字剪切/删除复制替换撤销和恢复跳转至指定行 vim底行模式下的命令集 gcc/ggcc/g的作用gcc/g的语法预处理编译汇编链接函数库动静态库动态链接的优缺点 静态链接的优缺点 vim…

注意,注意,weak_ptr有坑

class Test { public:Test(){cout << "构造函数\n";}~Test(){cout << "析构函数\n";} }; void *operator new(size_t nsize) {void *ptmp std::malloc(nsize);printf("申请内存:%d,%p\n",nsize, ptmp);return ptmp; }void operator…

【油猴脚本】学习笔记

目录 新建用户脚本模板源注释 测试代码获取图标 Tampermonkey v4.19.0 原教程&#xff1a;手写油猴脚本&#xff0c;几分钟学会新技能——王子周棋洛   Tampermonkey首页   面向 Web 开发者的文档   Greasy Fork 新建用户脚本 打开【管理面板】 点击【】&#xff0c;即…

微服务使用指南

微服务使用指南 1.初识微服务 微服务可以认为是一种分布式架构的解决方案&#xff0c;提供服务的独立性和完整性&#xff0c;做到服务的高内聚、低耦合。 目前服务架构主要包含&#xff1a;单体架构和分布式架构。 1.1 单体架构 单体架构&#xff1a;把所有业务功能模块都…

YoloV8目标检测与实例分割——目标检测onnx模型推理

一、模型转换 1.onnxruntime ONNX Runtime&#xff08;ONNX Runtime或ORT&#xff09;是一个开源的高性能推理引擎&#xff0c;用于部署和运行机器学习模型。它的设计目标是优化执行使用Open Neural Network Exchange&#xff08;ONNX&#xff09;格式定义的模型&#xff0c;…

微信怎么批量保存大量照片

8-2 本文要解决的问题是自动或者快速地保存微信收到的图片的事情&#xff0c;如果你的工作中有一个事情是需要每天或者经常保存大量的从微信收到的图片或者视频的&#xff0c;也许本文适合你&#xff0c;本文介绍的方法&#xff0c;可以自动保存各个群或者人发来的图片和视频。…

【LeetCode每日一题合集】2023.9.18-2023.9.24(⭐拓扑排序⭐设计数据结构:LRU缓存实现 LinkedHashMap⭐)

文章目录 337. 打家劫舍 III&#xff08;树形DP&#xff09;2560. 打家劫舍 IV&#xff08;二分查找动态规划&#xff09;LCP 06. 拿硬币&#xff08;简单贪心模拟&#xff09;2603. 收集树中金币⭐思路——拓扑排序删边 2591. 将钱分给最多的儿童&#xff08;分类讨论&#xf…

MATLAB_5MW风电永磁直驱发电机-1200V直流并网MATLAB仿真模型

仿真软件&#xff1a;matlab2016b 风机传动模块、PMSG模块、蓄电池模块、超级电容模块、无穷大电源、蓄电池控制、风机控制、逆变器控制等模块。 逆变器输出电压&#xff1a; 混合储能系统SOC&#xff1a; 威♥关注“电击小子程高兴的MATLAB小屋”获取更多精彩资料&#xff0…

String的几个常见面试题及其解析

String s3 new String("a") new String("b")会不会在常量池中创建对象&#xff1f; 答案&#xff1a;不会&#xff0c;首先需要解释“”字符串拼接的理解。 采用 运算符拼接字符串时&#xff1a; 如果拼接的都是字符串直接量&#xff0c;则在编译时编…

基于信号功率谱特征和GRNN广义回归神经网络的信号调制类型识别算法matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 MATLAB2022a 3.部分核心程序 ................................................................ %调制识别 len1 func_f…

【代码】【5 二叉树】d3

关键字&#xff1a; 非叶子结点数、k层叶子结点数、层次遍历、找双亲结点、找度为1、叶子结点数