CSS布局总结

438 阅读30分钟

水平居中

文本/行内/行内块级(推荐PC)

原理:text-align只控制行内内容(文字、行内元素、行内块级元素)如何相对于它的块级父元素对齐。

 #parent{text-align:center}

优点:简单快捷,兼容性好。

缺点:

  1. 只对行内内容有效;
  2. 属性会继承影响到后代行内内容;
  3. 如果子元素宽度大于父元素宽度则无效,但是后代行内内容中宽度小于设置text-align属性的元素宽度的时候,也会继承水平居中。

单个块级元素(推荐PC)

原理:在margin有结余的同时如果左右margin设置了auto,将会均分剩余空间。

另外,如果上下的margin设置了auto,其计算值为0。

 #parent {
   text-align: center;
   background-color: skyblue;
 }
 .son {
   /* 定宽 */
   width: 100px;
   /* 测试,可不指定高,用内容撑开 */
   height: 100px;
   margin: 0 auto;
   background-color: tomato;
 }

优点:简单快捷,兼容性好。

缺点:

  1. 必须定宽,并且值不能为auto
  2. 宽度要小于父元素,否则无效。

多个块级元素

原理:text-align只控制行内内容(文字、行内元素、行内块级元素)如何相对它的父元素对齐

 #parent {
   text-align: center;
   background-color: skyblue;
 }
 .son {
   display: inline-block;
   /* 测试,可不指定宽高,用内容撑开 */
   width: 100px;
   height: 50px;
   background-color: tomato;
 } /*改为行内或者行内块级形式,以达到text-align对其生效*/

优点:简单快捷,兼容性好

缺点:

  1. 只对行内内容有效;
  2. 属性会继承影响到后代行内内容;
  3. 块级元素改为inline-block 换行,空格会产生元素间隔。

使用绝对定位和负margin-left(推荐PC)

原理:子绝父相,toprightbottomleft的值是相对于父元素尺寸的,margin是相对于自身尺寸的,组合使用达到水平居中的目的。

 #parent {
   position: relative;
   height: 100px;
   background-color: skyblue;
 }
 ​
 .son {
   position: absolute;
   background-color: tomato;
   /* 测试,可不指定宽高,用内容撑开 */
   width: 200px;
   height: 100px;
   /* 子元素距离父元素开始位置是父元素宽度的一半*/
   left: 50%;
   /* 负 margin ,取值为子元素 width 的一半 */
   margin-left: -100px;
 }

优点:使用margin-left兼容性好;不管是块级元素还是行内元素都可以实现。

缺点:

  1. 代码较多;
  2. 脱离文档流;
  3. 使用margin-left需要知道宽度值。

使用绝对定位和margin:0 auto left:0 right:0 (推荐PC)

原理:left:0 right:0是子元素距离父元素的左右两边距离,为0则代表不设置子元素定宽,它会铺满整个父元素;

当我们使用定宽以后,使用margin:0 auto就可以平分剩余空间,实现水平居中。

 #parent {
   position: relative;
   height: 300px;
   background-color: skyblue;
 }
 .son {
   position: absolute;
   /* 定宽 */
   width: 300px;
   /* 测试,可不指定高,用内容撑开 */
   height: 200px;
   left: 0;
   right: 0;
   margin: 0 auto;
   background-color: tomato;
 }

优点:兼容性好;不管是块级元素还是行内元素都可以实现。

缺点:

  1. 代码较多;
  2. 脱离文档流。

使用绝对定位和transform:translateX(-50%)

原理:基本同上,只是使用transform:translateX(-50%)代替了负margin

 #parent {
   position: relative;
   height: 300px;
   background-color: skyblue;
 }
 .son {
   position: absolute;
   /* 定宽 */
   width: 200px;
   /* 测试,可不指定高,用内容撑开 */
   height: 200px;
   left: 50%;
   transform: translateX(-50%);
   background-color: tomato;
 }

优点:不需要算宽度值。

缺点:

  1. 代码较多;
  2. 脱离文档流;
  3. 使用transform兼容性不好(IE9+)。

使用flex

原理:就是设置当前主轴对齐方式为居中。

 #parent {
   display: flex;
   justify-content: center;
   background-color: skyblue;
 }
 .son {
   /* 定宽 */
   width: 200px;
   /* 测试,可不指定高,用内容撑开 */
   height: 200px;
   background-color: tomato;
 }

优点:功能强大;简单方便。

缺点:PC端兼容性不好,移动端(Andorid4.0+)。

小结

  • 对于水平居中,我们应该先考虑哪些元素自带的居中效果,最先想到的应该就是text-align:center,但这个只对行内内容有效,所以我们要用text-align:center就必须将子元素设置为display:inline或者display:inline-block
  • 其次就是考虑能不能用margin:0 auto,因为这是一句代码就能搞定的事;
  • 多个块级元素就用绝对定位去实现;
  • 移动端能用flex就用flex;如果不需要支持IE,PC端也建议使用flex

垂直居中

单行文本/行内/行内块级(推荐PC)

原理:同上

 #parent {
   height: 50px;
   line-height: 50px;
   background-color: skyblue;
 }
 .son {
   background-color: tomato;
 }

优点:简单;兼容性好。

缺点:只能用于单行行内内容;需要知道高度值。

多行文本/行内/行内块级

原理:

  1. 多行文字使用一个标签包裹,然后设置 displayinline-block。好处在于既能重置外部的 line-height 为正常的大小 ,又能保持内联元素特性, 从而可以设置vertical-align 属性,以及产生一个非常关键的“行框盒子”。我们需要的其实并不是这个“行框盒子”,而是每个“行框盒子”都会附带的一个产物—“幽灵空白节点(strut)”,即一个宽度为0、表现如同普通字符的看不见的“节点”。有了这个“幽灵空白节点(strut)”,我们的 line-height:300px 就有了作用的对象,从而相当于在.content元素前面撑起了一个高度为 300px 宽度为 0 的内联元素。
  2. 因为内联元素默认都是基线对齐的,所以我们通过对.content 元素设置 vertical-align:middle 来调整多行文本的垂直位置,从而实现我们想要的“垂直居中”效果。如果是要借助 line-height 实现图片垂直居中效果,也是类似的原理和做法。
 #parent {
   line-height: 300px;
   background-color: #f0f3f9;
 }
 .son {
   /* line-height 也可以设成 normal */
   line-height: 20px;
   display: inline-block;
   vertical-align: middle;
 }

优点:简单,兼容性好。

缺点:只能用于行内内容。近似垂直居中,一般使用问题不大。

图片(推荐PC)

原理:改造“幽灵空白节点(strut)”的基线位置可以使用 font-size,当字体足够小时,基线和中线会重合在一起。什么时候字体足够小呢?就是 0。

 #parent {
 font-size: 0; 
 height: 200px;
 line-height: 200px;
 }
 ​
 #parent img {
 vertical-align: middle;
 }

优点:简单,兼容性好。

缺点:需要添加font-size:0才能完全垂直居中。

也可以使用伪元素代替font-size:0

 #parent {
   height: 300px;
   background-color: skyblue;
 }
 ​
 #parent::after {
   content: '';
   height: 100%;
 }
 ​
 #parent::after,
 #parent > img {
   vertical-align: middle;
   display: inline-block;
 }
 img {
   background-color: tomato;
 }

优点:不需要重新设置font-size

缺点:代码比较多。

原理:当我们line-height设置的足够大,幽灵空白节点(strut)会起作用,这时候设置vertical-align就会达到近似垂直居中的效果。

 #parent {
   height: 128px;
   line-height: 128px; /* 关键 CSS 属性 */
   background-color: skyblue;
 }
 #parent > img{
   height: 96px;
   vertical-align: middle;
   background-color: tomato;
 }

单个块级元素

使用table-cell实现

原理:父级元素为td或者th时,vertical-align才会生效;

 #parent {
   display: table-cell;
   vertical-align: middle;
   border: 1px solid #000;
   height: 300px;
 }
 .son {
   width: 100px;
   height: 100px;
   background-color: skyblue;
 }

优点:元素高度可以动态改变,不需在CSS中定义,如果父元素没有足够空间,该元素内容也不会被截断。IE8开始支持。

缺点:

  1. 设置table-cell的元素,宽度和高度的值设置百分比无效,需要给它的父元素设置display: table
  2. table-cell不感知margin,在父元素上设置table-row等属性,也会使其不感知height
  3. 设置floatposition会对默认布局造成破坏,可以考虑为之增加一个父div定义float等属性;内容溢出时会自动撑开父元素。

使用绝对定位和负margin(推荐PC)

原理:子绝父相,toprightbottomleft的值是相对于父元素尺寸的,margin是相对于自身尺寸的,组合使用达到垂直居中的目的。

 #parent {
   position: relative;
   height: 300px;
   background-color: skyblue;
 }
 .son {
   position: absolute;
   /* 测试,可不指定宽高,用内容撑开 */
   height: 100px;
   width: 100px;
   top: 50%;
   margin-top: -50px;
   background-color: tomato;
 }

优点:使用margin-top兼容性好;不管是块级元素还是行内元素都可以实现。

缺点:

  1. 代码较多;
  2. 脱离文档流;
  3. 使用margin-top需要知道高度值。

使用绝对定位和margin:0 auto left:0 right:0 (推荐PC)

原理:top:0 bottom:0是子元素距离父元素的上下两边距离,为0则代表不设置子元素定高,它会铺满整个父元素;

当我们使用定高以后,使用margin:auto 0就可以平分剩余空间,实现垂直居中。

 #parent {
   position: relative;
   height: 500px;
   background-color: skyblue;
 }
 .son {
   position: absolute;
   /* 定高 */
   height: 100px;
   /* 测试,可不指定宽,用内容撑开 */
   width: 100px;
   top: 0;
   bottom: 0;
   margin: auto 0;
   background-color: tomato;
 }

优点:兼容性好;不管是块级元素还是行内元素都可以实现。

缺点:

  1. 代码较多;
  2. 脱离文档流。

使用绝对定位和transform:translateX(-50%)

原理:基本同上,只是使用transform:translateY(-50%)代替了负margin

 #parent {
   position: relative;
   height: 500px;
   background-color: skyblue;
 }
 .son {
   position: absolute;
   /* 测试,可不指定宽高,用内容撑开 */
   height: 100px;
   width: 100px;
   top: 50%;
   transform: translateY(-50%);
   background-color: tomato;
 }

优点:不需要算宽度值。

缺点:

  1. 代码较多;
  2. 脱离文档流;
  3. 使用transform兼容性不好(IE9+)。

使用flex实现任意元素垂直居中

原理:align-items属性将所有直接子节点上的align-self值设置为一个组。 align-self属性设置项目在其包含块中在交叉轴方向上的对齐方式。

 #parent {
   display: flex;
   align-items: center;
   /* 定高 */
   height: 500px;
   background-color: skyblue;
 }
 .son {
   /* 测试,可不指定宽高,用内容撑开 */
   height: 100px;
   width: 100px;
   background-color: tomato;
 }

原理:align-self 会对齐当前 gridflex 行中的元素,并覆盖已有的 align-items 的值。

 #parent {
   display: flex;
   /* 定高 */
   height: 500px;
   background-color: skyblue;
 }
 .son {
   align-self: center;
   background-color: tomato;
   /* 测试,可不指定宽高,用内容撑开 */
   height: 100px;
   width: 100px;
 }

优点:简单灵活;功能强大;

缺点:PC端兼容性不好,移动端(Android4.0+)。

总结:

  • 对于垂直居中,最先想到的应该就是 line-height 了,但是这个属性只用于行内内容;
  • 其次就是考虑使用vertical-align:middle
  • 再次考虑使用绝对定位;
  • 移动端能用flex就用flex;如果不需要支持IE,PC端也建议使用flex

水平垂直居中

行内/行内块级/图片(PC推荐)

原理:同上

 #parent {
 height: 300px;
 line-height: 300px; /*行高的值与height相等*/
 text-align: center;
 /*消除幽灵空白节点的bug*/
 font-size: 0;
 border: 1px solid #000;
 }
 ​
 img {
 /*display: inline-block;*/ /*如果是块级元素需改为行内或行内块级才生效*/
 vertical-align: middle;
 }

table-cell

原理:同上

 #parent {
   height: 150px;
   width: 200px;
   display: table-cell;
   vertical-align: middle;
   /*text-align: center;*/ /*如果是行内元素就添加这个*/
   background-color: skyblue;
 }
 .son {
   /*margin: 0 auto;*/ /*如果是块级元素就添加这个*/
   width: 100px;
   height: 50px;
   background-color: tomato;
 }

button作为父元素

原理:button的默认样式,再把需要居中的元素表现形式改为行内或行内块级就好。

 button#parent {
   /*改掉button默认样式就好了,不需要居中处理*/
   height: 150px;
   width: 200px;
   outline: none;
   border: none;
 }
 #son {
   display: inline-block; /*button自带text-align: center,改为行内水平居中生效*/
 }

优点:简单方便;

缺点:只适用于行内内容;需要清除部分默认样式;水平垂直居中兼容性很好,但是ie下点击会有凹陷效果。

绝对定位(PC推荐)

原理:子绝父相,toprightbottomleft的值是相对于父元素尺寸的,margin或者transform是相对于自身尺寸的,组合使用达到几何上的水平垂直居中。

 #parent {
   position: relative;
   height: 500px;
   width: 500px;
   background-color: skyblue;
 }
 .son {
   position: absolute;
   top: 50%;
   left: 50%;
   /*定宽高时等同于margin-left:负自身宽度一半;margin-top:负自身高度一半;*/
   transform: translate(-50%, -50%);
   width: 100px;
   height: 100px;
   background-color: tomato;
 }

优点:兼容性好;块级和行内元素都可以实现;

缺点:代码较多;脱离文档流;使用margin需要知道宽高;使用transform兼容性不好(ie9+)。

绝对定位2(PC推荐)

原理:

topbottomleftright都设置为0时,会默认占满整个空间;

margin设为auto时,会平分父元素剩余空间。

 #parent {
   position: relative;
   width: 800px;
   height: 600px;
   background-color: skyblue;
 }
 ​
 .son {
   height: 300px;
   width: 300px;
   position: absolute;
   top: 0;
   left: 0;
   bottom: 0;
   right: 0;
   margin: auto;
   background-color: tomato;
 }

优点:无需关注宽高,兼容性好(ie8+);

缺点:代码较多;脱离文档流。

使用flex

使用margin:auto

原理:探秘 flex 上下文中神奇的自动 margin

 /* 使用auto */
 #parent {
   display: flex;
   width: 800px;
   height: 500px;
   background-color: skyblue;
 }
 ​
 .son {
   margin: auto;
   width: 100px;
   height: 100px;
   background-color: tomato;
 }
 ​
 /* 第二种 */
 #parent {
   display: flex;
   justify-content: center;
   align-items: center;
   width: 800px;
   height: 500px;
   background-color: skyblue;
 }
 ​
 .son {
   width: 100px;
   height: 100px;
   background-color: tomato;
 }
 ​
 /* 第三种 */
 #parent {
   display: flex;
   justify-content: center;
   width: 800px;
   height: 500px;
   background-color: skyblue;
 }
 ​
 .son {
   align-self: center;
   width: 100px;
   height: 100px;
   background-color: tomato;
 }

优点:简单灵活;功能强大;

缺点:PC端不支持IE,移动端Android4.0+

视窗居中

原理:vh为视口单位,视口即文档可视的部分,50vh就是视口高度的50/100,设置margin-bottom:0是为了去掉滚动条。

 .son {
   height: 300px;
   width: 300px;
   border: 1px solid #000;
   margin: 50vh auto 0;
   transform: translateY(-50%);
 }

优点:简单;容易理解;两句代码达到屏幕水平垂直居中;

缺点:兼容性不好ie9+Android4.4+

扩展:水平垂直居中深入挖掘

总结:

  1. 单个元素的情况下,使用绝对定位就可以了;
  2. 多个元素的情况下,使用flex

单列布局

第一种

 <div class="header"></div>
 <div class="content"></div>
 <div class="footer"></div>
 .header,
 .content,
 .footer {
   margin: 0 auto;
   max-width: 960px;
 }
 ​
 .header {
   height: 100px;
   background-color: tomato;
 }
 .content {
   height: 600px;
   background-color: skyblue;
 }
 .footer {
   height: 100px;
   background-color: aqua;
 }

第二种(通栏)

 <div class="header"></div>
 <div class="center">
   <div class="content"></div>
 </div>
 <div class="footer"></div>
 .header {
   margin: 0 auto;
   height: 100px;
   background-color: pink;
 }
 .content {
   margin: 0 auto;
   height: 600px;
   width: 960px;
   background-color: aquamarine;
 }
 .footer {
   margin: 0 auto;
   height: 100px;
   background-color: skyblue;
 }

两列布局

左列定宽,右列自适应

使用float+margin(PC推荐)

 <div id="left">左侧定宽</div>
 <div id="right">右侧自适应</div>
 #left {
   float: left;
   width: 100px;
   height: 900px;
   background-color: skyblue;
 }
 #right {
   margin-left: 100px;
   height: 900px;
   background-color: pink;
 }

原理:left左浮动,脱离文档流;right为了不被left挡住,设置margin-left大于等于left的宽度已达到视觉上的两栏布局。

优点:代码简单;容易理解;兼容性好。

缺点:left的宽度和rightmargin-left需要对应且固定。

使用float+overflow(PC推荐)

 <div id="left">左侧定宽</div>
 <div id="right">右侧自适应</div>
 #left {
   float: left;
   width: 100px;
   height: 900px;
   background-color: skyblue;
 }
 #right {
   height: 900px;
   background-color: pink;
   /* 触发 BFC 达到自适应 */
   overflow: hidden;
 }

原理:left左浮动,right触发bfc达到自适应。

优点:代码简单;容易理解;无需关注定宽的宽度,利用bfc达到自适应效果。

使用绝对定位

 <div id="parent">
       <div id="left">左侧定宽</div>
       <div id="right">
         右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应
       </div>
 </div>
 #parent {
   position: relative;
 }
 #left {
   position: absolute;
   top: 0;
   left: 0;
   width: 100px;
   height: 900px;
   background-color: skyblue;
 }
 #right {
   position: absolute;
   top: 0;
   /* 值大于等于left的宽度 */
   left: 100px;
   right: 0;
   height: 900px;
   background-color: pink;
 }

原理:利用绝对定位算好宽高固定好两个盒子的位置。

优点:容易理解,兼容性好。

缺点:脱离文档流;右边盒子的left值需要等于左边的width

使用flex

 <div id="parent">
   <div id="left">左侧定宽</div>
   <div id="right">
     右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应
   </div>
 </div>
 #parent {
   display: flex;
   width: 100%;
   height: 900px;
 }
 #left {
   width: 100px;
   background-color: skyblue;
 }
 #right {
   /* 均分父元素剩余空间 */
   flex: 1;
   background-color: tomato;
 }

优点:简单灵活;功能强大。

缺点:PC端不支持IE,移动端Android4.0+

使用Grid

 <div id="parent">
   <div id="left">左侧定宽</div>
   <div id="right">
     右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应
   </div>
 </div>
 #parent {
   display: grid;
   grid-template-columns: 100px 1fr;
   width: 100%;
   height: 900px;
 }
 #left {
   background-color: skyblue;
 }
 #right {
   background-color: tomato;
 }

左列自适应,右列定宽

原理同上,只是左右交换位置,此处略。

一列不定,一列自适应

使用float+overflow(PC推荐)

 <div id="left">左侧不定宽。。。。。。。</div>
 <div id="right">
   右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应
 </div>
 #left {
   float: left;
   height: 900px;
   background-color: skyblue;
 }
 ​
 #right {
   overflow: hidden;
   height: 900px;
   background-color: pink;
 }

原理:left左浮动,right触发bfc达到自适应。

优点:代码简单;容易理解;无需关注定宽的宽度,利用bfc达到自适应效果。

使用flex

 <div id="parent">
 <div id="left">左侧不定宽。。。。。。。</div>
 <div id="right">
   右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应
 </div>
 </div>
 #parent {
   display: flex;
 }
 #left {
   height: 900px;
   background-color: skyblue;
 }
 #right {
   height: 900px;
   flex: 1;
   background-color: tomato;
 }

优点:简单灵活;功能强大。

缺点:PC端不支持IE,移动端Android4.0+

使用Grid

 <div id="parent">
 <div id="left">左侧不定宽。。。。。。。</div>
 <div id="right">
   右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应右侧自适应
 </div>
 </div>
 #parent {
   display: grid;
   grid-template-columns: auto 1fr;
 }
 #left {
   height: 900px;
   background-color: skyblue;
 }
 #right {
   height: 900px;
   background-color: tomato;
 }

优点:灵活划分网格区域;新型布局利器,适用于页面二维布局。

缺点:PC端不支持IE,移动端Android5.0+

总结:

  • 两列布局我们用的多的就是float
  • 除了浮动,我们可以使用绝对定位;
  • 允许的情况下,可以使用flexgrid

三列布局

两列顶宽,一列自适应

使用float+margin

 <div id="parent">
   <div id="left">左侧定宽</div>
   <div id="center">中间定宽</div>
   <div id="right">右侧自适应</div>
 </div>
 #parent {
   min-width: 960px;
 }
 #left {
   float: left;
   width: 100px;
   height: 900px;
   background-color: skyblue;
 }
 #center {
   float: left;
   width: 300px;
   height: 900px;
   background-color: pink;
 }
 #right {
   margin-left: 400px;
   height: 900px;
   background-color: tomato;
 }

原理:两个盒子浮动,另一个盒子计算好两个盒子的宽度。

优点:代码简单;容易理解。

缺点:marginpadding值要对应好;父元素宽度不够会换行。

使用float+overflow(PC推荐)

 <div id="parent">
   <div id="left">左侧定宽</div>
   <div id="center">中间定宽</div>
   <div id="right">右侧自适应</div>
 </div>
 #parent {
   min-width: 960px;
 }
 #left {
   float: left;
   width: 100px;
   height: 900px;
   background-color: skyblue;
 }
 #center {
   float: left;
   width: 300px;
   height: 900px;
   background-color: pink;
 }
 #right {
   /* 触发BFC */
   overflow: hidden;
   height: 900px;
   background-color: tomato;
 }

原理:两个盒子浮动,另一个盒子触发bfc达到自适应。

优点:无需关注定宽的宽度,使用bfc达到自适应。

缺点:父元素宽度不够,子元素会换行。

使用绝对定位

 <div id="parent">
   <div id="left">左侧定宽</div>
   <div id="center">中间定宽</div>
   <div id="right">右侧自适应</div>
 </div>
 #parent {
   position: relative;
 }
 #left {
   position: absolute;
   top: 0;
   left: 0;
   width: 100px;
   height: 900px;
   background-color: skyblue;
 }
 #center {
   position: absolute;
   left: 100px;
   top: 0;
   width: 300px;
   height: 900px;
   background-color: pink;
 }
 #right {
   position: absolute;
   left: 400px;
   top: 0;
   right: 0;
   height: 900px;
   background-color: tomato;
 }

原理:计算好盒子的宽度去设置位置。

优点:容易理解,兼容性好。

缺点:需动手计算宽度。

使用flex

 <div id="parent">
   <div id="left">左侧定宽</div>
   <div id="center">中间定宽</div>
   <div id="right">右侧自适应</div>
 </div>
 ​
 #parent {
   display: flex;
   height: 900px;
 }
 #left {
   width: 100px;
   height: 900px;
   background-color: skyblue;
 }
 #center {
   width: 300px;
   height: 900px;
   background-color: pink;
 }
 #right {
   flex: 1;
   height: 900px;
   background-color: tomato;
 }

优点:简单灵活;功能强大。

缺点:PC端不支持IE,移动端Android4.0+

使用Grid

 <div id="parent">
   <div id="left">左侧定宽</div>
   <div id="center">中间定宽</div>
   <div id="right">右侧自适应</div>
 </div>
 #parent {
   display: grid;
   grid-template-columns: 100px 200px 1fr;
   height: 900px;
 }
 #left {
   background-color: skyblue;
 }
 #center {
   background-color: pink;
 }
 #right {
   background-color: tomato;
 }

优点:灵活划分网格区域;新型布局利器,适用于页面二维布局。

缺点:PC端不支持IE,移动端Android5.0+

两侧定宽,中间自适应

双飞翼布局(PC推荐)

 <header>header</header>
 <div class="wrapper">
   <div class="col main">
     <div class="main-wrap">中间自适应</div>
   </div>
   <div class="col left">左侧定宽</div>
   <div class="col right">右侧定宽</div>
 </div>
 <footer>footer</footer>
 header,
 footer {
   height: 100px;
   background-color: pink;
 }
 .wrapper {
   overflow: hidden;
 }
 .col {
   float: left;
 }
 .main {
   width: 100%;
   background-color: skyblue;
 }
 .main-wrap {
   margin: 0 100px;
   height: 600px;
 }
 .left {
   margin-left: -100%;
   width: 100px;
   height: 600px;
   background-color: tomato;
 }
 .right {
   margin-left: -100px;
   width: 100px;
   height: 600px;
   background-color: tomato;
 }

思路:

  1. main增加一个内层 div main-wrap
  2. 使用float:leftleftrightmain在同一行;
  3. main设置width:100%实现自适应,此时leftright会掉下去;
  4. main-wrap设置margin:0 100px让左右两边留出间隙;
  5. 通过设置margin-leftleftrightmain同一行;
  6. 设置overflow:hidden清除浮动,让footer出现。

缺点:多加了一层dom树节点,增加渲染树生成的计算量。

扩展:聊聊为什么淘宝要提出「双飞翼」布局

圣杯布局

 <header>header</header>
 <div class="wrapper">
   <div class="col main">中间自适应</div>
   <div class="col left">左侧定宽</div>
   <div class="col right">右侧定宽</div>
 </div>
 <footer>footer</footer>
 header,
 footer {
   height: 100px;
   background-color: pink;
 }
 .wrapper {
   padding: 0 100px;
   overflow: hidden;
 }
 .col {
   float: left;
   position: relative;
 }
 .main {
   width: 100%;
   height: 600px;
   background-color: skyblue;
 }
 .left {
   margin-left: -100%;
   left: -100px;
   width: 100px;
   height: 600px;
   background-color: tomato;
 }
 .right {
   margin-left: -100px;
   right: -100px;
   width: 100px;
   height: 600px;
   background-color: tomato;
 }

思路:

  1. 使用float:leftleftrightmain在同一行;
  2. main设置width:100%实现自适应,此时leftright会掉下去;
  3. 通过设置margin-leftleftrightmain同一行;
  4. 通过设置父容器wrapperpadding,让左右两边留出间隙;
  5. 通过设置相对定位,让leftright移动到两边;
  6. 设置overflow:hidden清除浮动,让footer出现。

缺点:

  • main的最小宽度不能小于left部分的宽度,否则left会掉到下一行;
  • 如果其中一列内容高度拉长,其它两列的背景并不会自动填充。

使用绝对定位

 <header>header</header>
 <div class="wrapper">
   <div class="main">中间自适应</div>
   <div class="left">左侧定宽</div>
   <div class="right">右侧定宽</div>
 </div>
 <footer>footer</footer>
 header,
 footer {
   height: 100px;
   background-color: pink;
 }
 .wrapper {
   position: relative;
 }
 .main {
   margin: 0 100px;
   height: 600px;
   background-color: skyblue;
 }
 .left,
 .right {
   width: 100px;
   height: 600px;
   position: absolute;
   top: 0;
   background-color: tomato;
 }
 .left {
   left: 0;
 }
 .right {
   right: 0;
 }

缺点:高度不可控,如果left大于main,会单独溢出;

优点缺点
圣杯结构简单,无多余dom层中间部分宽度小于左侧时布局混乱
绝对定位结构简单,且无需清理浮动两侧高度无法支撑总高度
双飞翼支持各种宽高变化,通用性强dom结构多余层,增加渲染树生成的计算量

使用Grid

 <div class="container">
   <header>header</header>
   <div class="left">左侧定宽</div>
   <div class="main">中间自适应</div>
   <div class="right">右侧定宽</div>
   <footer>footer</footer>
 </div>
 .container {
   height: 800px;
   display: grid;
   grid-template-columns: 100px auto 100px;
   grid-template-rows: 100px auto 100px;
   grid-template-areas:
     'header header header'
     'left main right'
     'footer footer footer';
 }
 ​
 header {
   grid-area: header;
   background-color: pink;
 }
 footer {
   grid-area: footer;
   background-color: pink;
 }
 ​
 .left {
   grid-area: left;
   background-color: tomato;
 }
 .right {
   grid-area: right;
   background-color: tomato;
 }
 .main {
   grid-area: main;
   background-color: skyblue;
 }

使用flex

 <header>header</header>
 <div class="container">
   <div class="left">左侧定宽</div>
   <div class="main">中间自适应</div>
   <div class="right">右侧定宽</div>
 </div>
 <footer>footer</footer>
 header,
 footer {
   width: 100%;
   height: 100px;
   background-color: pink;
 }
 .container {
   display: flex;
   height: 600px;
 }
 .left,
 .right {
   width: 100px;
   background-color: tomato;
 }
 .main {
   flex: 1;
   background-color: skyblue;
 }

总结:

  • 首先推荐使用的是两列float+overflow
  • 如果不兼容IE可以使用flex或者grid

多列布局

等宽布局

四列等宽

使用float(PC推荐)

 <div class="container">
   <div class="column">
     1
     <p>测试文字测试文字测试文字...</p>
   </div>
   <div class="column">
     2
     <p>测试文字测试文字测试文字...</p>
   </div>
   <div class="column">
     3
     <p>测试文字测试文字测试文字...</p>
   </div>
   <div class="column">
     4
     <p>测试文字测试文字测试文字...</p>
   </div>
 </div>
 ​
 .container {
   margin-left: -20px;
 }
 ​
 .column {
   padding-left: 20px;
   width: 25%;
   float: left;
   box-sizing: border-box;
   border: 1px solid #000;
   /* 背景色从内容开始绘制,方便观察 */
   background-clip: content-box;
   height: 800px;
 }
 .column:nth-child(odd) {
   background-color: skyblue;
 }
 .column:nth-child(even) {
   background-color: tomato;
 }

原理:根据父元素空间宽度平分,子元素设置浮动,用padding去模拟间隔,再给父元素一个位移抵消第一个间隔。

优点:代码简单,易于理解;兼容性好(IE8+)。

缺点:

  1. 需手动清理浮动;
  2. 由于是百分比平分宽度不能设置margin,否则占位超出父元素宽度换行显示。

使用flex

 <div class="container">
   <div class="column">
     1
     <p>测试文字测试文字测试文字...</p>
   </div>
   <div class="column">
     2
     <p>测试文字测试文字测试文字...</p>
   </div>
   <div class="column">
     3
     <p>测试文字测试文字测试文字...</p>
   </div>
   <div class="column">
     4
     <p>测试文字测试文字测试文字...</p>
   </div>
 </div>
 .container {
   margin-left: -20px;
   height: 600px;
   display: flex;
 }
 ​
 .column {
   /* 平分container */
   flex: 1;
   margin-left: 20px;
 }
 .column:nth-child(odd) {
   background-color: skyblue;
 }
 .column:nth-child(even) {
   background-color: tomato;
 }

多列等宽

使用float(PC推荐)

 <div class="container">
 <div class="column">
   1
   <p>测试文字测试文字测试文字...</p>
 </div>
 <div class="column">
   2
   <p>测试文字测试文字测试文字...</p>
 </div>
 <div class="column">
   3
   <p>测试文字测试文字测试文字...</p>
 </div>
 <div class="column">
   4
   <p>测试文字测试文字测试文字...</p>
 </div>
 <div class="column">
   5
   <p>测试文字测试文字测试文字...</p>
 </div>
 .container {
   height: 600px;
 }
 ​
 .column {
   float: left;
   width: 20%;
   height: 600px;
 }
 .column:nth-child(odd) {
   background-color: skyblue;
 }
 .column:nth-child(even) {
   background-color: tomato;
 }

原理:根据父元素空间宽度平分,子元素设置浮动,用padding去模拟间隔,再给父元素一个位移抵消第一个间隔。

优点:代码简单,易于理解;兼容性好(IE8+)。

缺点:

  1. 需手动清理浮动;
  2. 由于是百分比平分宽度不能设置margin,否则占位超出父元素宽度换行显示。

使用flex

 <div class="container">
 <div class="column">
   1
   <p>测试文字测试文字测试文字...</p>
 </div>
 <div class="column">
   2
   <p>测试文字测试文字测试文字...</p>
 </div>
 <div class="column">
   3
   <p>测试文字测试文字测试文字...</p>
 </div>
 <div class="column">
   4
   <p>测试文字测试文字测试文字...</p>
 </div>
 <div class="column">
   5
   <p>测试文字测试文字测试文字...</p>
 </div>
 .container {
   height: 600px;
   display: flex;
 }
 ​
 .column {
   flex: 1;
 }
 .column:nth-child(odd) {
   background-color: skyblue;
 }
 .column:nth-child(even) {
   background-color: tomato;
 }

使用grid

 <div class="container">
 <div class="column">
   1
   <p>测试文字测试文字测试文字...</p>
 </div>
 <div class="column">
   2
   <p>测试文字测试文字测试文字...</p>
 </div>
 <div class="column">
   3
   <p>测试文字测试文字测试文字...</p>
 </div>
 <div class="column">
   4
   <p>测试文字测试文字测试文字...</p>
 </div>
 <div class="column">
   5
   <p>测试文字测试文字测试文字...</p>
 </div>
 .container {
   height: 600px;
   display: grid;
   grid-template-columns: repeat(5, 1fr);
 }
 .column:nth-child(odd) {
   background-color: skyblue;
 }
 .column:nth-child(even) {
   background-color: tomato;
 }

九宫格布局

使用table

 <div class="container">
   <div class="row">
     <div class="item">1</div>
     <div class="item">2</div>
     <div class="item">3</div>
   </div>
   <div class="row">
     <div class="item">4</div>
     <div class="item">5</div>
     <div class="item">6</div>
   </div>
   <div class="row">
     <div class="item">7</div>
     <div class="item">8</div>
     <div class="item">9</div>
   </div>
 </div>
 .container {
   width: 1200px;
   height: 600px;
   margin: 0 auto;
   display: table;
 }
 .row {
   display: table-row;
 }
 .item {
   border: 1px solid #000;
   display: table-cell;
 }

原理:table以表格的形式显示。

优点:代码简单;容易理解;适用于宽度高度未知情况;兼容性好(ie8+)。

缺点:

  1. margin失效;设置间隔比较麻烦;
  2. 设置table-cell的元素,宽度和高度的值设置百分比无效,需要给它的父元素设置display: table 才生效;
  3. table-cell不感知margin,在父元素上设置table-row等属性,也会使其不感知height
  4. 设置floatposition会对默认布局造成破坏,可以考虑为之增加一个父div定义float等属性;内容溢出时会自动撑开父元素。

使用flex

 <div class="container">
   <div class="row">
     <div class="item">1</div>
     <div class="item">2</div>
     <div class="item">3</div>
   </div>
   <div class="row">
     <div class="item">4</div>
     <div class="item">5</div>
     <div class="item">6</div>
   </div>
   <div class="row">
     <div class="item">7</div>
     <div class="item">8</div>
     <div class="item">9</div>
   </div>
 </div>
 .container {
   width: 1200px;
   height: 600px;
   margin: 0 auto;
   display: flex;
   flex-direction: column;
 }
 .row {
   display: flex;
   flex: 1;
 }
 .item {
   border: 1px solid #000;
   flex: 1;
 }

缺点:每三个一行,对于动态创建不确定数量的元素要控制好嵌套结构。

使用flex2

 <ul>
   <li>1</li>
   <li>2</li>
   <li>3</li>
   <li>4</li>
   <li>5</li>
 </ul>
 ul {
   width: 100%;
   list-style: none;
   display: flex;
   flex-wrap: wrap;
 }
 ​
 ul > li {
   width: 33.33333333333333%;
   height: 200px;
   box-sizing: border-box;
   border: 1px solid #000;
 }

原理:父元素flex并设置换行,子元素不设置伸缩,转而定宽设置宽三分之一,高度自定义,计算好宽度即能实现九宫格布局(也可以多列等宽布局)。

缺点:高度需要自定无法等宽。

使用grid

 <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>
 .container {
   width: 1200px;
   height: 600px;
   margin: 0 auto;
   display: grid;
   /*等同于1fr 1fr 1fr,此为重复的合并写法*/
   grid-template-columns: repeat(3, 1fr);
   grid-template-rows: repeat(3, 1r);
 }
 .item {
   border: 1px solid #000;
 }

全屏布局

使用绝对定位(PC推荐)

 <div class="container">
   <div class="top">top</div>
   <div class="left">left</div>
   <div class="right">right</div>
   <div class="bottom">bottom</div>
 </div>
 html,
 body,
 .container {
   height: 100%;
   overflow: hidden;
 }
 .container > div {
   border: 1px solid #000;
 }
 .top {
   position: absolute;
   top: 0;
   left: 0;
   right: 0;
   height: 100px;
 }
 ​
 .left {
   position: absolute;
   top: 100px;
   left: 0;
   bottom: 100px;
   width: 200px;
 }
 ​
 .right {
   position: absolute;
   overflow: auto;
   left: 200px;
   right: 0;
   top: 100px;
   bottom: 100px;
 }
 ​
 .bottom {
   position: absolute;
   left: 0;
   right: 0;
   bottom: 0;
   height: 100px;
 }

原理:计算好盒子的宽度和间隔去设置位置。

优点:容易理解;兼容性好。

缺点:代码繁多;需要计算好各个盒子的位置。

使用flex

 <div class="container">
   <div class="top">top</div>
   <div class="main">
     <div class="left">left</div>
     <div class="right">right</div>
   </div>
   <div class="bottom">bottom</div>
 </div>
 html,
 body,
 .container {
   height: 100%;
 }
 .container {
   display: flex;
   flex-direction: column;
 }
 .container > div {
   border: 1px solid #000;
 }
 .top {
   height: 100px;
 }
 .bottom {
   height: 100px;
 }
 .main {
   flex: 1;
   display: flex;
 }
 .left {
   width: 200px;
   border: 1px solid #000;
 }
 .right {
   flex: 1;
   overflow: auto;
   border: 1px solid #000;
 }

使用grid

 <div class="container">
   <div class="top">top</div>
   <div class="left">left</div>
   <div class="right">right</div>
   <div class="bottom">bottom</div>
 </div>
 html,
 body,
 .container {
   height: 100%;
 }
 .container {
   width: 100%;
   height: 100%;
   display: grid;
   grid-template-columns: 200px 1fr;
   grid-template-rows: 100px auto 100px;
   grid-template-areas:
     'header header'
     'aside main'
     'footer footer';
 }
 .container > div {
   border: 1px solid #000;
 }
 .top {
   grid-area: header;
 }
 .bottom {
   grid-area: footer;
 }
 ​
 .left {
   grid-area: aside;
 }
 .right {
   grid-area: main;
 }

等高布局

使用正padding+负margin

 <div class="container">
   <div class="left">left</div>
   <div class="center">center</div>
   <div class="right">right</div>
 </div>
 .container {
   width: 100%;
   overflow: hidden;
 }
 .center,
 .left,
 .right {
   float: left;
   width: 33%;
   padding-bottom: 9999px;
   margin-bottom: -9999px;
 }
 .center {
   background-color: skyblue;
 }
 .left {
   background-color: tomato;
 }
 .right {
   background-color: tomato;
 }

原理:因为背景是在 padding 区域显示的,设置一个大数值的 padding-bottom,再设置相同数值的负的 margin-bottom,使背景色铺满元素区域,又符合元素的盒模型的计算公式,实现视觉上的等高效果。

缺点:背景图失效,只有纯色背景才有用。

使用flex

 <div class="container">
   <div class="left">left</div>
   <div class="center">center</div>
   <div class="right">right</div>
 </div>
 .container {
   width: 100%;
   display: flex;
 }
 .center {
   flex: 1;
   background-color: skyblue;
 }
 .left {
   background-color: tomato;
 }
 .right {
   background-color: tomato;
 }

使用grid

 <div class="container">
   <div class="left">left</div>
   <div class="center">center</div>
   <div class="right">right</div>
 </div>
 .container {
   display: grid;
   grid-auto-flow: column;
 }
 .center {
   background-color: skyblue;
 }
 .left {
   background-color: tomato;
 }
 .right {
   background-color: tomato;
 }

参考:

16种方法实现水平居中垂直居中

[各种页面常见布局+知名网站实例分析+相关阅读推荐]

只要一行代码,实现五种 CSS 经典布局

【CSS】CSS布局解决方案(终结版)

几种常见的CSS布局