盘点常见的HTML+CSS布局

314 阅读11分钟

传统布局

正常流布局,正常流的布局方式就是使用display去设置盒模型加上float在配合上position去实现

等分布局

等分布局的要求是多列的情况下,保证每一列在视角中的宽度是相同的。 DOM文档

<div class="outer">
  <div class="inner"></div>
  <div class="inner"></div>
  <div class="inner"></div>
</div>

CSS部分

.inner {
  width: 33.33%;
  height: 300px;
  display: inline-block;
  /* float: left */
  outline: 1px solid blue;/*注意border会占用空间,outline不占用空间,不会影响元素的尺寸和位置,
border 可应用于几乎所有有形的html元素,而 outline 是针对链接、表单控件和ImageMap等元素设计*/
}
.outer {
  font-size: 0;
} /* 如果用的是inline-block会出先一个问题,第三个元素换行了,原因是inner元素后面的空白被识别为了空
白文本,可以改变outer中的字号为0: */

等高布局

等高布局的要求也是在多列的情况下,每一列的内容高度不同,要保证每一列的高度和最长列的高度相同。

负margin + padding(伪等高)

子元素高度差依然存在,只是视觉上给人感觉就是等高,通过负margin和Padding实现,这种方式采用了padding补偿法:

  • 把列的padding-bottom设为一个足够大的值。
  • 把列的margin-bottom设为一个与padding-bottom的正值相抵消的负值。
  • 父容器设置溢出隐藏 DOM文档
 <div class="layout parent">
        <div class="left"><p>left</p></div>
        <div class="center">
            <p>我是中间部分的内容</p>
            <p>我是中间部分的内容</p>
            <p>我是中间部分的内容</p>
            <p>我是中间部分的内容</p>
        </div>
        <div class="right"><p>right</p></div>
        <div style="clear: both;">11111111111</div>
    </div>

CSS部分

.parent{
    position: relative;
    overflow:hidden;
    color: #efefef;
}
.center,
.left,
.right {
    box-sizing: border-box;
    float: left;
}
.center {
    background-color: #2ECC71;
    width: 60%;
}

.left {
    width: 20%;
    background-color: #1ABC9C;
}
.right {
    width: 20%;
    background-color: #3498DB;
}
.left,
.right,
.center  {
    margin-bottom: -99999px;
    padding-bottom: 99999px;
}

使用absolute实现

<div class="layout parent">
        <div class="left"><p>left</p> </div>
        <div class="center">
            <p>我是中间部分的内容</p>
            <p>我是中间部分的内容</p>
            <p>我是中间部分的内容</p>
            <p>我是中间部分的内容</p>
        </div>
        <div class="right"><p>right</p></div>
    </div>

CSS部分

.parent{
        position: absolute;
        color: #efefef;
        width:100%;
        height: 200px;
    }

    .left,
    .right,
    .center {
        position: absolute;
        box-sizing: border-box;
        top:0;
        bottom:0;
    }
    .center {
        background-color: #2ECC71;
        left: 200px;
        right: 300px;
    }

    .left {
        width: 200px;
        background-color: #1ABC9C;
    }
    .right {
        right:0;
        width: 300px;
        background-color: #3498DB;
    }

两列自适应布局

两列自适应布局的布局要求一边固定宽或不固定,而另一边占据剩下的部分达到自适应。这种布局有时候会应用在后台系统,经常左边导航右边内容,或者有的页面左边或右边广告剩下的主题

float+margin

这种方法的处理是让左边浮动,右边margin-left左边元素宽度,达到左边固定宽右边自适应。

DOM文档

<div class="outer">
  <div class="left"></div>
  <div class="right"></div>
</div>

CSS部分

.left {
  float: left;
  width: 100px;
}
.right {
  margin-left: 100px;
}

float + overflow(BFC)

仍然按照上面的结构,这种方式是左边元素浮动,右边元素利用overflow触发BFC,不与外界元素有任何瓜葛。达到左边不固定宽右边自适应。

.left {
 float: left;
}
.right {
 overflow: hidden;
}

三列自适应布局

三列自适应布局通常指的是两边宽度固定,中间一列宽度自适应,它的应用场景有很多,许多商城的PC首页都采用了这种布局,经典的圣杯布局和双飞翼布局也是其中一种。

流体布局(float+margin)和BFC(float+overflow)

  • 这两种方法的前提都是左右两边元素分别对应左右浮动,然后中间自适应元素利用margin挤出位置,或使用BFC来扯清关系。
  • 这两种方法的不同是margin需要确定左右两边的宽度,而BFC不需要。但是他们也有相同的缺点,就是主要内容.center无法最先加载,当页面内容较多时会影响用户体验。 DOM文档
<div class="outer">
  <div class="left"></div>
  <div class="right"></div>
  <div class="center"></div>
</div>

CSS部分

.left {
  float: left;
  width: 100px;
}
.right {
  float: right;
  width: 120px;
}
.center {
  margin-left: 100px;
  margin-right: 120px;
  /* 如果是BFC可以去掉上面的margin */
  /* overflow: hidden; */
}

绝对定位(absolute)

  • 利用两边元素绝对定位脱离文档流到左右两边,中间元素利用margin隔离两边。
  • 这种方法操作简单,但绝对定位是脱离文档流的,意味着下面的所有子元素也会脱离文档流,高度未知的时候,会有问题,这就导致了这种方法的有效性和可使用性是比较差的。(比如你在后面要添加一个新的元素,由于脱离了文档流,后面的元素无法正常排列,你仍然需要使用绝对定位去找它应该在的位置,如果后面添加的元素再多一点还有可能发生重叠等问题。) DOM文档
<div class="outer">
  <div class="center"></div>
  <div class="left"></div>
  <div class="right"></div>
</div>

CSS部分

.outer {
  position: relative;
}
.center {
  margin-left: 100px;
  margin-right: 120px;
}
.left {
  position: absolute;
  top: 0;
  left: 0;
  width: 100px;
}
.right {
  position: absolute;
  top: 0;
  right: 0;
  width: 120px;
}

圣杯和双飞翼布局

圣杯布局起源于2006年发在a list part上的文章:In Search of the Holy Grail · An A List Apart Article,双飞翼布局是圣杯布局的优化版,由淘宝UED提出。它们都是两边顶宽,中间自适应的三栏布局,中间栏要在放在文档流前面以优先渲染。 DOM文档

<div class="header">header</div>
<div class="outer">
  <div class="center">center</div>
  <div class="left">left</div>
  <div class="right">right</div>
</div>
<div class="footer">footer</div>

CSS部分 1(基本样式)

.header {
      height: 40px;
      background: lightblue;
}
.footer {
      height: 80px;
      background: lightcoral;
}
.center {
  width: 100%;/* 因为中间部分要自适应窗口的变化,所以设定宽度为100% */
  height: 100px;
  background-color: peachpuff;
}
.left {
  width: 100px;
  height: 110px;
  background-color: skyblue;
}
.right {
  width: 120px;
  height: 120px;
  background-color: pink;
}

CSS部分 2(让 left,right,center浮动起来)

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

CSS部分 3(清除浮动,使 footer显示出来,DOM文档中在 outer后加一个 clearfix类(省略))

.clearfix::after {
  content: "";
  display: block;
  clear: both;
}

CSS部分 4(让 left,right,center到对应的位置)

.left {
  margin-left: -100%;
}
.right {
  margin-left: -120px;
}

到这里会发现,center字样无法显示,针对这个问题圣杯布局和双飞翼布局分别使用了两种不同的解决方式。

圣杯布局

当 center 宽度比两边的元素宽度小的时候,布局就会乱掉。可以通过设置 center 的 min-width 属性或使用双飞翼布局避免问题。

CSS部分 5

.left {
  position: relative;
  left:-100px;
}
.right {
  position: relative;
  left: 120px;/* 移动左右元素,占据父元素padding的位置 */
}
.outer {
  padding-left: 100px;
  padding-right:120px;/* 改变.center宽度,使它的宽度刚好等于父元素 - 左边元素宽度 - 右边元素宽度 */
}

双飞翼布局

双飞翼布局给中间自适应部分添加了一个子元素作为内容面板,并且为它添加margin来控制自己的显示范围,从而解决文字覆盖问题。

DOM文档(给 center 加一个子元素 center-content)

 <div class="center">
    <div class="center-content">center</div>
  </div>

CSS部分 5'

.center-content {
  margin-left: 100px;  
  margin-right: 120px; 
}

布局的传统解决方案,基于盒状模型,依赖display属性 +position属性 +float属性。但它对于那些特殊布局非常不方便,比如,垂直居中就不容易实现。传统的布局是为了文档结、构而生的,只是随着业务需要,有很多“改变盒的大小,使得它们的结构保持固定”的要求,才研究出了margin负值等这些黑科技搭配,但仍然不好理解也会有一些副作用。在这种情况下,Flex布局被随着CSS3一起提出来解决这种问题。

Flex布局

Flex 是 Flexible Box 的缩写,意为"弹性布局",用来为盒状模型提供最大的灵活性。任何一个容器都可以指定为Flex布局,而这个容器我们称作flex容器,它的所有子元素自动成为容器成员,称为flex项目。 使用一个flex布局的方法是设置元素的display属性为flex或者inline-flex,Webkit内核的浏览器,必须加上-webkit-前缀。

等分布局

DOM文档

<div class="container">
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
</div>

CSS部分

.container {
  display: flex;
}
.item {
  flex-grow: 1;
}

等高布局

DOM文档

<div class="container">
  <div class="child"></div>
  <div class="child"></div>
</div>

CSS部分

.container {
  display: flex;
}
.child {
  align-items: stretch; /* 实际上有默认 */
}

两列自适应布局

DOM文档

<div class="container">
  <div class="left">left</div>
  <div class="right">right</div>
</div>

CSS部分

.container {
  display: flex;
}
.right {
  flex-grow: 1;
}

三列自适应布局

因为flex的默认效果会一行显示,中间元素设置的width: 100%;会因为可缩小特性而变化,因此两边要固定住宽度,设置其可缩小属性为flex-shrink: 0,在空间发生变化的时候,大小不会被缩减。

DOM文档

<div class="container">
  <div class="left">left</div>
  <div class="center">center</div>
  <div class="right">right</div>
</div>

CSS部分

.container {
  display: flex;
}
.center {
  width: 100%;
}
.left {
  width: 100px;
  flex-shrink: 0;
}
.right {
  width: 200px;
  flex-shrink: 0;
}

flex布局总的来说确实非常好用,但是它唯一的问题在于兼容性,flex 只支持IE10+,因此使用的时候也要考虑好场景。另外还有一种更为强大的布局方式grid。

Grid 布局与 Flex布局有一定的相似性,都可以指定容器内部多个项目的位置。但是,它们也存在重大区别。Flex 布局是轴线布局,只能指定"项目"针对轴线的位置,可以看作是一维布局。Grid 布局则是将容器划分成"行"和"列",产生单元格,然后指定"项目所在"的单元格,可以看作是二维布局。Grid 布局远比 Flex 布局强大。

Grid网格布局

网格布局(Grid)是最强大的 CSS 布局方案。它将网页划分成一个个网格,可以任意组合不同的网格,做出各种各样的布局。Grid 布局的属性分成两类。一类定义在容器上面,称为容器属性;另一类定义在项目上面,称为项目属性。 使用一个grid布局的方法是设置元素的display属性为grid或者inline-grid。在caniuse 中可以看grid的兼容性,总体兼容性还不错,但在 IE 10 以下不支持。

三列自适应布局

左右固定,中间自适应

DOM文档

<div class="container">
    <div class="left">left</div>
    <div class="middle">middle</div>
    <div class="right">right</div>
</div>

CSS部分

.container {
    display: grid;
    grid-template-columns: 100px 1fr 100px;
    height: 200px;
}
.container div {
    text-align: center;
}
.left {
    background: greenyellow;
}
.middle {
    background: lightblue;
}
.right {
    background: greenyellow;
}

九宫格

DOM文档

<div class="container">
    <div class="item">1</div>
    <div class="item">2</div>
    <div class="item">3</div>
    <div class="item">4</div>
    <div class="item">5</div>
    <div class="item">6</div>
    <div class="item">7</div>
    <div class="item">8</div>
    <div class="item">9</div>
</div>

CSS部分

.container {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    grid-template-rows: repeat(3, 1fr);
    height: 400px;
    width: 400px;
    grid-gap: 8px;
}
.item {
    background: lightskyblue;
}

圣杯布局和双飞翼布局

DOM文档

<div class="container">
    <div class="header">header</div>
    <div class="left">left</div>
    <div class="body">body</div>
    <div class="right">right</div>
    <div class="footer">footer</div>
</div>

CSS部分

.container {
    display: grid;
    grid-template-columns: 100px 1fr 100px;
    grid-template-rows: 50px 300px 50px;
}
.header {
    grid-area: 1 / 1 / 2 / 4;
    background: lightsalmon;
}
.left {
    background: lightseagreen;
}
.body {
    background: lightslategray;
}
.right {
    background: lightyellow;
}
.footer {
    grid-area: 3 / 1 / 4 / 4;
    background: yellowgreen;
}

repeat + auto-fit——固定列宽,改变列数量

需求有时候会希望我们的网格能够固定列宽,并根据容器的宽度来改变列的数量。这个时候,我们可以用repeat() 函数以及 auto-fit 关键字。grid-template-columns: repeat(auto-fit, 200px) 表示固定列宽为 200px,数量是自适应的,只要容纳得下,就会往上排列。

DOM文档

<div class="wrapper">
  <div class="one item">One</div>
  <div class="two item">Two</div>
  <div class="three item">Three</div>
  <div class="four item">Four</div>
  <div class="five item">Five</div>
  <div class="six item">Six</div>
  <div class="seven item">Seven</div>
  <div class="eight item">eight</div>
  <div class="nine item">Nine</div>
</div>

CSS部分

.wrapper {
  margin: 50px;
  display: grid;
  grid-template-columns: repeat(auto-fit, 200px);
  grid-gap: 10px 20px;
  grid-auto-rows: 50px;
}

.one {
  background: #19CAAD;
}
.two { 
  background: #8CC7B5;
}
.three {
  background: #D1BA74;
}
.four {
  background: #BEE7E9;
}
.five {
  background: #E6CEAC;
}
.six {
  background: #ECAD9E;
}
.seven {
  background: #BEEDC7;
}
.eight {
  background: #F4606C;
}
.nine {
  background: #A0EEE1;
}
.item {
  text-align: center;
  font-size: 200%;
  color: #fff;
}

repeat+auto-fit+minmax 去掉右侧空白

.wrapper {
  margin: 50px;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  grid-gap: 10px 20px;
  grid-auto-rows: 50px;
}

repeat+auto-fit+minmax-span-dense 解决空缺问题

.wrapper {
  margin: 50px;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  grid-gap: 10px 20px;
  grid-auto-rows: 50px;
}

.wrapper {
  margin-top: 200px;
  grid-auto-flow: row dense;
}

居中

Grid 居中

三连击

给容器设置 display: grid; align-items: center; justify-content: center;

<div class="box">
  <div class="child">hello</div>
</div>

<style>
.box {
  width: 200px;
  height: 200px;
  border: 1px solid;
  display: grid;
  align-items: center;
  justify-content: center;
}
.child {
  background: red;
}  
</style>

margin: auto

给容器设置 display: grid; 子项设置 margin: auto;

<div class="box">
  <div class="child">hello</div>
</div>

<style>
.box {
  width: 200px;
  height: 200px;
  border: 1px solid;
  display: grid;
}
.child {
  background: red;
  margin: auto;
}  
</style>

Flex 居中

三连击

容器设置 display: flex; align-items: center; justify-content: center;

<div class="box">
  <div class="child">hello</div>
</div>

<style>
.box {
  width: 200px;
  height: 200px;
  border: 1px solid;
  display: flex;
  align-items: center;
  justify-content: center;
}
.child {
  background: red;
}  
</style>

margin: auto

给容器设置 display: flex; 子项设置 margin: auto;

<div class="box">
  <div class="child">hello</div>
</div>

<style>
.box {
  width: 200px;
  height: 200px;
  border: 1px solid;
  display: flex;
}
.child {
  background: red;
  margin: auto;
}  
</style>

绝对定位实现居中

容器设置position: relative。孩子设置 position: absolute; left: 50%; top: 50%; transfrom: translate(-50%, -50%);

<div class="box">
  <div class="child">hello</div>
</div>

<style>
.box {
  width: 200px;
  height: 200px;
  border: 1px solid;
  position: relative;
}
.child {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  background: red;
}  
</style>

借用line-height 居中

给容器加给伪元素,设置line-height等于容器的高度。给孩子设置display: inline-block;

<div class="box">
  <div class="child">hello</div>
</div>

<style>
.box {
  width: 200px;
  height: 200px;
  border: 1px solid;
  text-align: center;
}
.box::after {
  content: "";
  line-height: 200px;
}
.child {
  display: inline-block;
  background: red;
}
  
</style>

其他方法

容器设置position: relative。孩子设置 position: absolute; 设置固定宽度和高度;top、left、bottom、right都设置为0; margin设置为auto;也能实现垂直水平居中。

<div class="box">
  <div class="child">hello</div>
</div>

<style>
.box {
  width: 200px;
  height: 200px;
  border: 1px solid;
  position: relative;
}
.child {
  background: red;
  width: 100px;
  height: 40px;
  position: absolute;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
  margin: auto;
}  
</style>

参考

等高布局常用几种方式_个人文章 - SegmentFault 思否

CSS重塑(3)——CSS布局

Grid布局简介 - 云+社区 - 腾讯云

(已更)居中有哪几种实现方式 · 语雀

最强大的 CSS 布局 -- Grid 布局