CSS常见布局大汇总

  此文包括的布局类型有:未知宽高元素的水平垂直居中、 两栏等高、两栏布局、三栏布局(包括双飞翼布局和圣杯布局),三栏布局之固定高度中间自适应,除了代码外,还有笔者的一点个人理解,若是有所错误或不足的,欢迎大家指出!

未知宽高元素的水平垂直居中

<div class="container">
  <div class="ele">hello world</div>
</div>

为了便于观察,先设置一些css样式: 
.container {
  width: 200px;
  height: 200px;
  background-color: #eee;
}
.ele {
  background-color: rgb(179, 174, 174);
}
 
复制代码

将下面任一种方法的css样式分别添加到上面的代码中,都能得到下图这个效果。

方法一:绝对定位 + 平移

.contaienr {
  position: relative;
}
.ele {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  // 若宽高已知,还可以使用margin-left,margin-right代替
}
复制代码
// 若是ele指定了宽高,还可以设置距上下左右都为0再自动间隔
// 若没有设置宽高就直接使用的话,ele的宽高都会是父元素的100%
.ele {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  margin: auto;
  width: 100px;
  height: 100px;
}
复制代码

方法二:tabel布局

.container {
  display: table-cell;
  text-align: center;
  vertical-align: middle;
}
.ele {
  display: inline-block;  // 可选,若不加则ele的宽度将是父元素的100%
}
复制代码

方法三: flex布局

.container {
  display: flex;
  justify-content: center;
  align-items: center;
}
复制代码

两栏等高

padding内补偿法

<div class="box">
  <div class="left">
    <p>左浮动</p>
    <p>左浮动</p>
    <p>左浮动</p>
  </div>
  <div class="right">
    <p>也是左浮动</p> 
    <p>也是左浮动</p> 
    <p>也是左浮动</p> 
    <p>也是左浮动</p> 
    <p>也是左浮动</p> 
    <p>也是左浮动</p> 
  </div> 
</div>

.box { 
  overflow: hidden;
}
 .left {
  width: 50px;
  float: left;
  background-color: yellow;
  padding-bottom: 2000px;
  margin-bottom: -2000px;
}
.right {
  width: 100px;
  float: left;
  background-color: red;
  padding-bottom: 2000px;
  margin-bottom: -2000px;
}
复制代码

两栏等高的原理是,给每一栏都设置一个很大的padding-bottom的值,以此来弥补高度较小的那一栏。再使用一个等大的负的margin-bottom来收缩,正如我在另一篇文章里我解释的,使用负margin-bottom收缩后,虽然元素自身的宽高没有改变,但它的元素框会随着减小,最终元素框的高度取决于两栏中较高一栏。这时如果给它们的父元素添加overflow: hidden,则会隐藏掉溢出元素框的部分内容,于是就达到了高度较低的一栏和较高的一栏等高的效果。

但是使用padding内补偿法有一个缺陷,如果每一栏设置了border的话,因为每一栏的高被padding撑高而且隐藏了超出的内容,所以border-bottom是显示不出来的。解决办法是,再在每一栏的最后一个子元素设置一个div来模仿border-bottom。记得还要给父元素box设置为相对定位,才能让伪border-bottom定位到那一栏的底部。

.border {
  width: 52px;
  height: 2px;
  background-color: blue;
  position: absolute;
  bottom: 0;
}

复制代码

使用div模仿border-bottom还是有一个限制,就是必须先设置好那一栏的宽度,才好给border设置width。使用width: calc(100% + 2px)是没用的,因为每一栏都没有相对定位,所以100%是参考box而言的。如果要给每一栏设置相对定位,则border的绝对定位是相对于每一栏而言的,显示的边框又会被隐藏掉了。

tabel布局

利用表格(table)中每个单元格(table-cell)等高的特性

// IE8以下不支持
.box { 
  display: table;
  overflow: hidden;
}
.left {
  width: 50px;
  background-color: yellow;
  display: table-cell;
}
.right {
  width: 100px;
  background-color: red;
  display: table-cell;
}
复制代码

flex布局

.box {
  display: flex;
}
.left {
  background-color: blue;
  width: 100px;
}
.right {
  background-color: yellow;
}
复制代码

js / jq动态设置

在js代码里去获取box里每一栏的高度并取它们的最大值,再将每一栏的高度设置为该最大值。但这不可避免会操作到DOM,难免对性能造成影响。

两栏布局

左栏固定宽度,右栏自适应。

利用负margin

实现逻辑请看盒模型和负margin这篇文章里的解释。

<!-- content放在slider后面 -->
<div class="box">
  <div class="slider">
    <p>slider</p>
  </div>
  <div class="content">
    <p>content</p>
    <p>content</p>
    <p>content</p>
    <p>content</p>
  </div>
</div>

.box {
  overflow: hidden
}
.slider {
  float: left;
  width: 100px;
  height: 200px;
  background-color: blue;
}
.content {
  float: left;
  width: 100%;
  height: 200px;
  background-color: yellow;
  margin-right: -100px;
}
.content p {
  margin-right: 100px;
}
复制代码
<!-- content放在slider前面 -->
<div class="box">
  <div class="content">
    <p>content</p>
    <p>content</p>
    <p>content</p>
    <p>content</p>
  </div>
  <div class="slider">
    <p>slider</p>
  </div>
</div>

.slider {
  float: left;
  width: 100px;
  height: 200px;
  background-color: blue;
  margin-left: -100%;
}
.content {
  float: left;
  width: 100%;
  height: 200px;
  background-color: yellow;
}
.content p {
  margin-left: 100px;
}
复制代码

绝对定位

两栏都绝对定位并使用calc计算自适应那一栏的宽度

<div class="box">
  <div class="slider">
    <p>slider</p>
  </div>
  <div class="content">
    <p>content</p>
    <p>content</p>
    <p>content</p>
    <p>content</p>
  </div>
</div>

.box {
  position: relative;
}
.slider {
  width: 100px;
  height: 200px;
  background-color: blue;
  position: absolute;
  left: 0;
}
.content {
  width: 100%;
  height: 200px;
  background-color: yellow;
  position: absolute;
  left: 100px;
}
复制代码

tabel布局

利用表格的宽度等于所有单元格宽度之和的特性

<div class="box">
  <div class="slider">
    <p>slider</p>
  </div>
  <div class="content">
    <p>content</p>
    <p>content</p>
    <p>content</p>
    <p>content</p>
  </div>
</div>

.box {
  display: table;
  width: 100%;
}
.slider {
  width: 100px;
  display: table-cell;
  background-color: blue;
}
.content {
  display: table-cell;
  background-color: yellow;
}
复制代码

flex布局

flex大法真香

<div class="box">
  <div class="slider">
    <p>slider</p>
  </div>
  <div class="content">
    <p>content</p>
    <p>content</p>
    <p>content</p>
    <p>content</p>
  </div>
</div>

.box {
  display: flex;
}
.slider {
  background-color: blue;
  width: 100px;
}
.content {
  background-color: yellow;
  flex: 1;
}
复制代码

grid布局

<div class="box">
  <div class="slider">
    <p>slider</p>
  </div>
  <div class="content">
    <p>content</p>
    <p>content</p>
    <p>content</p>
    <p>content</p>
  </div>
</div>

.box {
  display: grid;
  grid-template-rows: 100px;
  grid-template-columns: 100px auto;
}
.slider {
  background-color: blue;
}
.content {
  background-color: yellow;
}
复制代码

三栏布局

跟两栏布局差不多,三栏布局是左右两栏固定宽度,中间栏自适应宽度(即固比固布局)。

浮动

<div class="box">
  <div class="left">
    <p>我是左导航栏我是左导航栏我是左导航栏</p>
  </div>
  <div class="right">
    <p>我是右导航栏我是右导航栏我是右导航栏</p>
  </div> 
  <div class="content">
    <div class="inner-content">
      <p>我是内容主题部分</p>
      <p>我是内容主题部分</p>
      <p>我是内容主题部分</p>
      <p>我是内容主题部分</p>
    </div>
  </div>
</div>
<!-- 注意,中间元素要放最后,使左右两栏先渲染,否则右栏会被挤压在下面 -->

.content {
  background-color: blue;
}
.inner-content {
  margin-left: 100px;
  margin-right: 100px;
}
.left {
  float: left;
  width: 100px;
  background-color: red;
}
.right {
  float: right;
  width: 100px;
  background-color: yellow;
}
复制代码

从效果图中可以看出,使用浮动实现三栏布局在中间栏容纳得下内容时是可以正常工作的,但内容一旦超出,中间栏就会向下扩展。如果给它们指定 height 的话自然就不存在这问题了,不过内容还是会溢出来的(见下图)。当然我们可以选择给外层容器box设置overflow: hidden来隐藏,但如果我们要显示全部内容的话要怎么办?答案是给左中右三个元素使用padding内补偿法,使它们三栏等高。(当浏览器宽度小于左右两栏的宽度和时,右栏会被挤下来,这时要也只能去给 body 设置min-width了,这点跟圣杯布局一样)。

绝对定位

<div class="box">
  <div class="left">
    <p>我是左导航栏我是左导航栏我是左导航栏</p>
  </div>
  <div class="content">
    <div class="inner-content">
      <p>我是内容主题部分</p>
      <p>我是内容主题部分</p>
      <p>我是内容主题部分</p>
      <p>我是内容主题部分</p>
    </div>
  </div>
  <div class="right">
    <p>我是右导航栏我是右导航栏我是右导航栏</p>
  </div> 
</div>

.box {
  position: relative;
}
.content {
  background-color: blue;
}
.inner-content {
  margin-left: 100px;
  margin-right: 100px;
}
.left {
  width: 100px;
  background-color: red;
  position: absolute;
  left: 0;
  top: 0;
}
.right {
  width: 100px;
  background-color: yellow;
  position: absolute;
  right: 0;
  top: 0;
}
复制代码

也存在内容大于中间栏宽度,中间栏会向下扩展的问题。

flex布局

<div class="box">
  <div class="left">
    <p>我是左导航栏我是左导航栏我是左导航栏</p>
  </div>
  <div class="content">
    <div class="inner-content">
      <p>我是内容主题部分</p>
      <p>我是内容主题部分</p>
      <p>我是内容主题部分</p>
      <p>我是内容主题部分</p>
    </div>
  </div>
  <div class="right">
    <p>我是右导航栏我是右导航栏我是右导航栏</p>
  </div> 
</div>

.box {
  display: flex;
}
.content {
  background-color: blue;
  flex: 1;
}
.left {
  width: 100px;
  background-color: red;
}
.right {
  width: 100px;
  background-color: yellow;
}
复制代码

对高度会自适应,内容超出时三栏会自动调整高度。

tabel布局

<div class="box">
  <div class="left">
    <p>我是左导航栏我是左导航栏我是左导航栏</p>
  </div>
  <div class="content">
    <div class="inner-content">
      <p>我是内容主题部分</p>
      <p>我是内容主题部分</p>
      <p>我是内容主题部分</p>
      <p>我是内容主题部分</p>
    </div>
  </div>
  <div class="right">
    <p>我是右导航栏我是右导航栏我是右导航栏</p>
  </div> 
</div>

.box {
  display: table;
  width: 100%;
}
.content {
  background-color: blue;
  display: table-cell;
}
.left {
  width: 100px;
  background-color: red;
  display: table-cell;
}
.right {
  width: 100px;
  background-color: yellow;
  display: table-cell;
}
复制代码

对高度会自适应,内容超出时三栏会自动调整高度。

grid布局

<div class="box">
  <div class="left">
    <p>我是左导航栏我是左导航栏我是左导航栏</p>
  </div>
  <div class="content">
    <div class="inner-content">
      <p>我是内容主题部分</p>
      <p>我是内容主题部分</p>
      <p>我是内容主题部分</p>
      <p>我是内容主题部分</p>
    </div>
  </div>
  <div class="right">
    <p>我是右导航栏我是右导航栏我是右导航栏</p>
  </div> 
</div>

.box {
  display: grid;
  grid-template-columns: 100px auto 100px;
}
.content {
  background-color: blue;
}
.left {
  background-color: red;
}
.right {
  background-color: yellow;
}
复制代码

对高度会自适应,内容超出时三栏会自动调整高度。

双飞翼布局

<div class="box">
  <div class="content">
    <div class="inner-content">
      <p>我是内容主题部分</p>
      <p>我是内容主题部分</p>
      <p>我是内容主题部分</p>
      <p>我是内容主题部分</p>
      <p>我是内容主题部分</p>
      <p>我是内容主题部分</p>
      <p>我是内容主题部分</p>
      <p>我是内容主题部分</p>
    </div>
  </div>
  <div class="left">
    <p>我是左导航栏我是左导航栏我是左导航栏</p>
  </div>
  <div class="right">
    <p>我是右导航栏我是右导航栏我是右导航栏</p>
  </div> 
</div>

.left {
  width: 100px;
  height: 100px;
  background-color: red;
  float: left;
  margin-left: -100%;
}
.right {
  width: 100px;
  height: 100px;
  background-color: yellow;
  float: left;
  margin-left: -100px;
}
.content {
  width: 100%;
  height: 100px;
  float: left;
  background-color: blue;
}
.inner-content {
  margin-left: 100px;
  margin-right: 100px;
}
复制代码

同样是使用浮动,但双飞翼布局是对负margin的应用,实现详情请看负margin实现两栏布局。同样的是,在HTML代码部分也是把content放到left和right前面的优先渲染 ,否则left放前面的话会造成left被content覆盖或是内容超出视图,也存在前面的那两个问题。听说双飞翼布局是淘宝创造的?

圣杯布局

<div class="box">
  <div class="content">
    <div class="inner-content">
      <p>我是内容主题部分</p>
      <p>我是内容主题部分</p>
      <p>我是内容主题部分</p>
      <p>我是内容主题部分</p>
    </div>
  </div>
  <div class="left">
    <p>我是左导航栏我是左导航栏我是左导航栏</p>
  </div>
  <div class="right">
    <p>我是右导航栏我是右导航栏我是右导航栏</p>
  </div> 
</div>

body {
  min-width: 400px;
}
.box { 
  padding: 0 100px 0 100px;
}
.left {
  width: 100px;
  height: 100px;
  background-color: red;
  float: left;
  margin-left: -100%;
  position: relative;
  left: -100px;
}
.right {
  width: 100px;
  height: 100px;
  background-color: yellow;
  float: left;
  margin-left: -100px;
  position: relative;
  right: -100px;
}
.content {
  width: 100%;
  height: 100px;
  float: left;
  background-color: blue;
}
复制代码

圣杯布局和双飞翼布局同样是对负margin的应用,区别在于解决中间栏内容不被左右侧边栏遮挡的方法不同。双飞翼布局是直接给content设置一个子div,利用margin-left和margin-right来间隔开彼此。而圣杯布局给父容器box设置padding来间隔开content主体内容和左右的距离,再给左右两栏分别相对定位设置left和right使其回到原先的位置。圣杯布局潜在的问题是,但浏览器缩小到一定程度后,左右两栏会被挤下来,不过可以给body设置min-width来解决这个问题。个人比较推荐双飞翼布局,两者实现的效果是一样的,而圣杯布局又要用到相对定位甚至min-width,为什么不简单点直接用margin解决同样的问题呢,不仅思路简单些代码也简洁。

三栏布局总结

  • 普通的浮动布局和双飞翼布局圣杯布局: 在 HTML 代码上普通的浮动是把中间栏放到最后,左右两栏分别左右浮动后中间空出来的空间给中间栏。而双飞翼布局和圣杯布局是把中间栏放在最前面使其先渲染,让三栏都左浮动后再利用左栏margin-left: -100%,右栏margin-left: -100px使其都并排布局。   因为普通浮动里是把中间栏放到最后才渲染的,所以当页面内容较多时可能会影响用户体验。

  • 对高度的适应性: 如果没有设置高度,flex布局,table布局,grid布局对三栏的高度变化有适应性,即使内容超出了三栏会都自动扩大自身高度来适应。而浮动和绝对定位两种方法内容一旦超出,中间栏则会向下扩展,双飞翼布局也一样有这问题,可以直接设置height来避免这问题。或者使用padding内补偿法使三栏都等高。

  • 局限性: 浮动和绝对定位脱离文档流,需要处理好和其他元素的位置关系,不过兼容性比较好。

  flex布局和grid布局是新生的布局方式,功能强大对高度的适应性好,但对浏览器的兼容性不是很好。

  table布局适应性好,对浏览器的兼容性也好,但table布局好像一直受人诟病,似乎毛病很多?我没在项目里用到过,也不知道真假。

三栏布局之固定高度中间自适应

上下固定高度,中间自适应。都需要使用overflow: scroll来使中间栏溢出的部分在内部滚动,否则中间栏会扩展自身高度把底栏挤出视图,这我也不知道有什么更好的解决办法了。

绝对定位

<div class="box">
  <div class="top">
    <p>我是头部</p>
    <p>我是头部</p>
    <p>我是头部</p>
    <p>我是头部</p>
  </div>
  <div class="content">
    <div class="inner_content">
      <p>我是内容主题部分</p>
      <p>我是内容主题部分</p>
      <p>我是内容主题部分</p>
      <p>我是内容主题部分</p>
      <p>我是内容主题部分</p>
      <p>我是内容主题部分</p>
    </div>
  </div> 
  <div class="bottom">
      <p>我是底部</p>
      <p>我是底部</p>
      <p>我是底部</p>
  </div>
</div>

.box {
  width: 100%;
  height: 100vh;
  position: relative;
}
.content {
  width: 100%;
  height: 100%;
  background-color: blue;
  overflow: scroll;
}
.top {
  width: 100%;
  height: 100px;
  background-color: red;
  position: absolute;
  left: 0;
  top: 0;
}
.bottom {
  width: 100%;
  background-color: yellow;
  position: absolute;
  left: 0;
  bottom: 0;
}
.inner_content {
  padding-top: 100px;
}
复制代码

此处使用绝对定位有一个局限,需要事先知道顶部栏的高度,才好给中间栏的内容部分设置padding-top,否则内容会被顶部栏遮住。对于中间栏需要使用overflow: scroll来使溢出部分在中间栏里滚动,否则中间栏会向下扩展。

flex布局

<div class="box">
  <div class="top">
    <p>我是头部</p>
    <p>我是头部</p>
    <p>我是头部</p>
  </div>
  <div class="content">
    <div class="inner_content">
      <p>我是内容主题部分</p>
      <p>我是内容主题部分</p>
      <p>我是内容主题部分</p>
      <p>我是内容主题部分</p>
    </div>
  </div> 
  <div class="bottom">
      <p>我是底部</p>
      <p>我是底部</p>
      <p>我是底部</p>
  </div>
</div>

.box {
  width: 100%; 
  height: 100vh;
  display: flex;
  flex-direction: column;
}
.content {
  width: 100%;
  flex: 1;
  background-color: blue;
  overflow: scroll;
}
.top {
  width: 100%;
  background-color: red;
}
.bottom {
  width: 100%;
  background-color: yellow;
}
复制代码

中间栏同样需要使用overflow: scroll

grid布局

<div class="box">
  <div class="top">
    <p>我是头部</p>
    <p>我是头部</p>
    <p>我是头部</p>
  </div>
  <div class="content">
    <div class="inner_content">
      <p>我是内容主题部分</p>
      <p>我是内容主题部分</p>
      <p>我是内容主题部分</p>
      <p>我是内容主题部分</p>
    </div>
  </div> 
  <div class="bottom">
      <p>我是底部</p>
      <p>我是底部</p>
      <p>我是底部</p>
  </div>
</div>

.box {
  width: 100%;
  height: 100vh;
  display: grid;
  grid-template-rows: 100px auto 100px;
  grid-template-columns: 100%;
}
.content {
  background-color: blue;
}
.top {
  background-color: red;
}
.bottom {
  background-color: yellow;
}
复制代码

中间栏同样需要使用overflow: scroll

收官

  笔者暂时只想到这些常见的布局,若是有所缺漏的,欢迎大家指出,笔者会再做补充。

  最后附Blog原文笔者Github,欢迎大家一起交流学习~

转载于:https://juejin.im/post/5c94da60e51d450fd87d6db7

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值