文章目录
  1. 1. 前戏:居中方案
    1. 1.1. 水平居中
      1. 1.1.1. inline-block + text- align
      2. 1.1.2. table + margin
      3. 1.1.3. absolute + transform
      4. 1.1.4. flex + justify-content
    2. 1.2. 垂直居中
      1. 1.2.1. table-cell + vertical-align
      2. 1.2.2. absolute + transform
      3. 1.2.3. flex + align-items
    3. 1.3. 水平 + 垂直居中
      1. 1.3.1. inline-block + text-align + table-cell + vertical-align
      2. 1.3.2. absolute + transform
      3. 1.3.3. flex + justify-content + align-items
    4. 1.4. 总结
  2. 2. 多列布局
    1. 2.1. 一列定宽,一列自适应布局
      1. 2.1.1. float + margin
      2. 2.1.2. float + margin (fix)
      3. 2.1.3. float + overflow
      4. 2.1.4. table布局
      5. 2.1.5. flex布局
    2. 2.2. 两列定宽,一列自适应
    3. 2.3. 一列不定宽加一列自适应
      1. 2.3.1. float + overflow
      2. 2.3.2. table布局
      3. 2.3.3. flex布局
    4. 2.4. 多列不定宽加一列自适应
    5. 2.5. 多列等分布局
      1. 2.5.1. 难点剖析
      2. 2.5.2. float
      3. 2.5.3. table布局
      4. 2.5.4. flex布局
    6. 2.6. 多列等高,其中一列宽度自适应
      1. 2.6.1. table布局
      2. 2.6.2. flex布局
      3. 2.6.3. float
  3. 3. 全屏布局
    1. 3.1. Position解决方案
    2. 3.2. flex解决方案
    3. 3.3. gird解决方案
    4. 3.4. 总结对比
  4. 4. 其它布局
    1. 4.1. 全等四宫格布局
    2. 4.2. 两侧定宽,中间自适应布局
    3. 4.3. 水平列表的底部对齐
  5. 5. 学习资料

好久没写CSS了,总结归纳一下css的布局方案,尽可能详细,也能让自己再温习一遍。PS:吐血整理,这也许是史上最全的布局方案了。

前戏:居中方案

水平居中

要求:如下图。子容器和父容器的宽度都未知,子容器相对父容器水平居中。

1
2
3
4
5
6
/* 
* 由于右侧目录
* 占用宽度较大
* 建议使用桌面浏览器
* 以获得最佳的浏览体验
*/

水平居中

inline-block + text- align

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
<div class="parent">
<div class="child">Demo</div>
</div>

<style>
.child {
display: inline-block; /* 根据内容自适应宽度 */
}
.parent {
text-align: center; /* 使内容居中 */
}
</style>

详解:text-align只对inline的子元素起作用,因此把子元素设置为了inline-block

优点:兼容性很好,原生支持到IE8;更低版本的IE也可通过hack手段实现兼容。
缺点:子容器会继承到父容器的text-align: center属性。

table + margin

代码示例:

1
2
3
4
5
6
7
8
9
10
<div class="parent">
<div class="child">Demo</div>
</div>

<style>
.child {
display: table;
margin: 0 auto;
}
</style>

详解:table在表现上类似于block元素,但是有区别,因为block宽度是撑满整行的,而table的宽度是随内容宽度自适应的。再利用block元素常用的margin: 0 auto;,即可实现居中。

优点:无需设置父元素,也可以兼容到IE8。
缺点:兼容IE6,7时需把整体结构调整为table。

absolute + transform

代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<div class="parent">
<div class="child">Demo</div>
</div>

<style>
.parent {
position: relative;
}
.child {
position: absolute;
left: 50%;
transform: translateX(-50%);
}
</style>

详解:子元素设为absolute可确定其宽度,然后根据父元素定位,此时子元素的最左边是父元素正中间,再根据子元素自身宽度进行位移。
优点:脱离文档流,因此居中的元素不会对其它元素造成影响。
缺点:用到了CSS3,因此最低只能兼容到IE9。

flex + justify-content

代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<div class="parent">
<div class="child">Demo</div>
</div>

<style>
.parent {
display: flex;
justify-content: center;
}
/* 或者下面的方法,可以达到一样的效果 */
.parent {
display: flex;
}
.child {
justify-content;
}
</style>

详解:flex容器的子项的默认宽度是auto,然后利用flex提供的justify-content实现水平居中,或使用传统的justify-content也可以。
优点:只需设置父节点属性,无需设置子元素
缺点:最高只兼容到IE9

垂直居中

要求:如下图。子容器和父容器的高度都未知,子容器相对父容器垂直居中。

垂直居中

table-cell + vertical-align

代码示例:

1
2
3
4
5
6
7
8
9
10
<div class="parent">
<div class="child">Demo</div>
</div>

<style>
.parent {
display: table-cell;
vertical-align: middle;
}
</style>

详解:vertical-align可作用到inline元素以及table-cell元素上面。
优点:只需设置父元素即可,能兼容到IE8
缺点:兼容IE6,7时需把整体结构调整为table。

absolute + transform

详解:和上文中absolute + transform实现水平居中的方式一样,因此优缺点也一样,不再赘述。

flex + align-items

详解:和上文flex + justify-content解决水平居中方式一样,把justify-content替换为align-items即可。优缺点也一样,不再赘述。

水平 + 垂直居中

要求:如下图。子容器和父容器的宽高都未知,子容器相对父容器水平垂直居中。

水平垂直居中

inline-block + text-align + table-cell + vertical-align

代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<div class="parent">
<div class="child">Demo</div>
</div>

<style>
.parent {
text-align: center;
display: table-cell;
vertical-align: middle;
}
.child {
display: inline-block;
}
</style>

详解:综合了上文的两种方法,text-align: center;display: inline-block;实现了水平居中,display: table-cell;vertical-align: middle;实现了垂直居中
优点:兼容性好,最低兼容到IE8。
缺点:兼容IE6,7时需把整体结构调整为table。

absolute + transform

代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<div class="parent">
<div class="child">Demo</div>
</div>

<style>
.parent {
position: relative;
}
.child {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
</style>

详解:和上文中absolute + transform实现水平居中方案一样,加入了垂直居中的代码(原理一样)。
优点:脱离文档流,因此居中的元素不会对其它元素造成影响。
缺点:用到了CSS3,因此最低只能兼容到IE9。

flex + justify-content + align-items

代码示例:

1
2
3
4
5
6
7
8
9
10
11
<div class="parent">
<div class="child">Demo</div>
</div>

<style>
.parent {
display: flex;
justify-content: center;
align-items: center;
}
</style>

详解:和上文flex容器实现水平居中一样,新加入了垂直居中代码。
优点:只需设置父节点属性,无需设置子元素
缺点:最高只兼容到IE9

总结

文章所列方案不一定是全的,可能还有其他方案。做解决方案,有一个大致的思路,我们可以这样来总结一下。

首先,我们需要了解css里面很多属性的值,以及它的一些特性,比如说flex,vertical-align等,要熟练掌握这些特性。然后,我们需要去分解问题。最后,把这些问题和css特性做一些联系,去解决问题。

多列布局

一列定宽,一列自适应布局

要求:如下图。子容器和父容器的宽高都未知,子容器相对父容器水平垂直居中。

一列定宽,一列自适应

float + margin

代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<div class="parent">
<div class="left">
<p>left</p>
</div>
<div class="right">
<p>right</p>
<p>right</p>
</div>
</div>

<style>
.left {
float: left;
width: 100px;
}
.right {
margin-left: 100px
/*间距可再加入 margin-left */
}
</style>

详解:非常基础的浮动布局,不解释。
优点: 1.兼容性非常好,2.简单
缺点: 1.耦合度较高 2.有一个‘bug’,右边第一个p元素清除浮动时会掉下去。这一般不是我们希望看到的效果。

float + margin (fix)

代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<div class="parent">
<div class="left">
<p>left</p>
</div>
<div class="right-fix">
<div class="right">
<p>right</p>
<p>right</p>
</div>
</div>
</div>

<style>
.left {
float: left;
width: 100px;
position: relative;/*层级提高,否则会被fix覆盖*/
}
.right-fix {
float: right;
width: 100%;
margin-left: -100px;
}
.right {
margin-left: 100px
/*间距可再加入 margin-left */
}
</style>

详解:相较原生的浮动布局,右边新增了一层空的标签,通过设置margin-left: -100px;,防止容器掉下去。
优点: 兼容性非常好
缺点: 1.耦合度较高;2.新增了一层结构

float + overflow

代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<div class="parent">
<div class="left">
<p>left</p>
</div>
<div class="right">
<p>right</p>
<p>right</p>
</div>
</div>

<style>
.left {
float: left;
width: 100px;
}
.right {
overflow: hidden;
}
</style>

详解:设置 overflow: hidden 会触发 BFC 模式(Block Formatting Context)块级格式化文本。 BFC 中的内容与外界的元素是隔离的。
优点:简单
缺点:不兼容IE6

table布局

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<div class="parent">
<div class="left">
<p>left</p>
</div>
<div class="right">
<p>right</p>
<p>right</p>
</div>
</div>

<style>
.parent {
display: table;
width: 100%;
table-layout: fixed;
}
.left {
display: table-cell;
width: 100px;
}
.right {
display: table-cell;
/*宽度为剩余宽度*/
}
</style>

详解:table布局的一个特点是,两列每一列的宽度之和一定是等于整个表格的,所以仅需设置一边宽度即可。 table-layout: fixed; 可加速渲染,更重要的作用是设定布局优先
优点:兼容性高
缺点: 1.table与普通布局不同,有些细节需要注意,比如不能设置margin,只能设置padding来控制间距。2.代码量较多。

flex布局

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<div class="parent">
<div class="left">
<p>left</p>
</div>
<div class="right">
<p>right</p>
<p>right</p>
</div>
</div>

<style>
.parent {
display: flex;
}
.left {
width: 100px;
margin-left: 20px;
}
.right {
flex: 1;
/*等价于*/
/*flex: 1 1 0;*/
}
</style>

详解:上文说过,flex的子项宽度默认是auto,因此需设置flex: 1;来自动撑满剩余宽度
优点:写法非常简单,理解起来也很简单。
缺点: 1.低版本浏览器不兼容。2.性能问题导致不能应用为大范围布局。

两列定宽,一列自适应

常用方案:float,flex
代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<div class="parent">
<div class="left">
<p>left</p>
</div>
<div class="center">
<p>center<p>
</div>
<div class="right">
<p>right</p>
<p>right</p>
</div>
</div>

<style>
.left, .center {
float: left;
width: 100px;
margin-right: 20px;
}
.right {
overflow: hidden;
}
</style>

效果:

一列不定宽加一列自适应

要求:如下图。

难点剖析:左侧的宽度由其内容宽度决定,右侧自适应。因此,需要依赖某一项元素宽度的布局是肯定不适合的,如float + margin布局。

float + overflow

详解:一列定宽,一列自适应布局所示,左侧宽度可设置为任意值,右侧宽度会随其变化。

table布局

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<div class="parent">
<div class="left">
<p>left</p>
</div>
<div class="right">
<p>right</p>
<p>right</p>
</div>
</div>

<style>
.parent {
display: table;
width: 100%;
}
.left,.right {
display: table-cell;
}
.left {
width: 0.1%;
}
</style>

详解:删掉table-layout: fixed;改为内容优先,把左侧宽度设为足够小,然后用内容把宽度撑开。
优点:兼容性较好,支持IE8及以上。
缺点:无法兼容IE6,7。

flex布局

详解:详见上文中一列定宽,一列自适应布局中的flex方案。无需更改,flex天生就有这种特性。

多列不定宽加一列自适应

详解:其实和两列不定宽加一列自适应是一样的,解决方案也是上述方案。

多列等分布局

要求:如下图。每一列的宽度和间距都是一样的

多列等分布局

难点剖析

如果没有间距,在n列中,可轻松得出每一列的宽度是1 / n;而一旦加上间距,那么最后一列一定是会出问题的,因为超出了父容器,如图:

所以如果使用浮动布局,可能存在这样的问题。那么怎么解决呢?

剖析

如上图,可以得出公式:总宽度C = W * N + G * ( n - 1) => C = W * N + G * N - G;转化可得:C + G = (W + G) * N;

float

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<div class="parent">
<div class="column">
<p>1</p>
</div>
<div class="column">
<p>2</p>
</div>
<div class="column">
<p>3</p>
</div>
<div class="column">
<p>4</p>
</div>
</div>
<style media="screen">
.parent {
margin-left: -20px;
}
.column {
float: left;
width: 25%;
padding-left: 20px;
box-sizing: border-box;
}
</style>

详解:如下图,通过margin-left: -20px使整个容器向左增加了20px,通过设置padding-left: 20px;box-sizing: border-box;使每列宽度包含了padding值。

优点:兼容性较好,至少兼容到IE8( IE6,7对百分比的浮点数计算有问题,所以并不能算完美兼容 )
缺点:结构样式耦合度较高。

table布局

代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<div class='parent-fix'>
<div class="parent">
<div class="column">
<p>1</p>
</div>
<div class="column">
<p>2</p>
</div>
<div class="column">
<p>3</p>
</div>
<div class="column">
<p>4</p>
</div>
</div>
</div>

<style media="screen">
.parent-fix {
margin-left: -20px;
}
.parent {
display: table;
width: 100%;
/*可以布局优先,也可以单元格宽度平分在没有设置的情况下*/
table-layout: fixed;
}
.column {
display: table-cell;
padding-left: 20px;
}
</style>

详解:table布局的特性决定了它的每一列天然都是平分的,因此不需要设置宽度。由于不支持margin,因此需在最外边再嵌套一层div,设置margin-left: -20px;
优点:零耦合,可随意调整列数。
缺点:写法较繁琐,需额外嵌套div。

flex布局

代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<div class="parent">
<div class="column">
<p>1</p>
</div>
<div class="column">
<p>2</p>
</div>
<div class="column">
<p>3</p>
</div>
<div class="column">
<p>4</p>
</div>
</div>

<style media="screen">
.parent {
display: flex;
}
.column {
/*等价于 flex: 1 1 0;*/
flex: 1;
}
.column+.column {
margin-left: 20px;
}
</style>

详解:利用flex: 1;平均分配剩余空间,.column+.column在这里指除了第一个.column的所有.column。
优点:代码量很少;零耦合,可随意调整列数
缺点:低版本浏览器不兼容。

多列等高,其中一列宽度自适应

要求:如下图,右侧自适应,两侧的高度需随时保持一致

多列等高

table布局

代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<div class="parent">
<div class="left">
<p>left</p>
</div>
<div class="right">
<p>right</p>
<p>right</p>
</div>
</div>

<style>
.parent{
display: table;
width: 100%;
table-layout: fixed;
}
.left,.right{display: table-cell;}
.left{
width: 100px;
border-right: 10px solid transparent;
background-color: #83B600;
background-clip: padding-box;
}
.right{
background-color: #F48A56;
}
</style>

详解:table的特性天生适合这种需求,但设置背景色时需注意:使用padding-right的方案来处理间距会存在部分兼容问题,为了解决这个兼容性问题,我们可以去掉padding-right的设置,变成border-right:20px solid transparent,然后把background-clilp改成padding-box,问题就解决了。
优点:原生支持的等高。
缺点:写法较繁琐。

flex布局

代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<div class="parent">
<div class="left">
<p>left</p>
</div>
<div class="right">
<p>right</p>
<p>right</p>
</div>
</div>

<style>
.parent {
display: flex;
}
.left {
width: 100px;
margin-left: 20px;
}
.right {
flex: 1;
/*等价于*/
/*flex: 1 1 0;*/
}
</style>

详解:flex 默认的 align-items 的值为 stretch。所以无需多做设置,天然就是等高的。
优点:写法非常简单。
缺点:低版本浏览器不兼容。

float

代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<div class="parent">
<div class="left">
<p>left</p>
</div>
<div class="right">
<p>right</p>
<p>right</p>
</div>
</div>

<style>
.parent {
overflow: hidden;
}
.left,
.right {
padding-bottom: 9999px;
margin-bottom: -9999px;
}
.left {
float: left;
width: 100px;
margin-right: 20px;
}
.right {
overflow: hidden;
}
</style>

详解:通过margin-bottompadding-bottom抵消掉,给父容器加上overflow: hidden;,这样的话,设置背景色时会把多余的padding-bottom截掉,高度取最高一列的高度,下边看不见的地方全都是它们的padding-box区域。所以其实这是一种伪等高,只是看上去一样高了而已。
优点:兼容性很好。
缺点:伪等高,且新手较难理解。

全屏布局

示例:

适用类型:

  • 管理系统
  • 监控平台
  • 统计平台

示例图稿:

顶部和底部定高,侧栏定宽,主栏和全局自适应屏幕宽高

Position解决方案

代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<div class="parent">
<div class="header"></div>
<div class="lside"></div>
<div class="content">
<div class="inner">
主内容区
</div>
</div>
<div class="footer"></div>
</div>
<style>
html,body,.parent{margin: 0;padding: 0;height: 100%;overflow: hidden;}
.header{
position: absolute;
top: 0;left: 0;right: 0;
height: 100px;
background: #EB4C54;
}
.lside{
position: absolute;
top: 100px;left: 0;bottom: 50px;
width: 200px;
background: #2D313D;
}
.content{
position: absolute;
top: 100px;right: 0;bottom: 50px;left: 200px;
background: #F0F0F0;
overflow: auto;
}
.footer{
position: absolute;
bottom: 0;left: 0;right: 0;
height: 50px;
background: #EB4C54;
}
/* 辅助,用于测试是否出现滚动条 */
.content .inner{
min-width: 500px;
min-height: 1000px;
}
</style>

详解:全局设置overflow: hidden;用来ban掉滚动条。主内容区设置overflow: auto;用来内容超出时在内容区显示滚动条。

兼容性:绝大多数浏览器都是兼容的,IE6对position的支持度不是很好,不过可以使用hack来解决。

flex解决方案

代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<div class="parent">
<div class="header">header</div>
<div class="center">
<div class="lside">lside</div>
<div class="content">
<div class="inner">
主内容区
</div>
</div>
</div>
<div class="footer">footer</div>
</div>
<style>
html,body,.parent{margin: 0;padding: 0;height: 100%;overflow: hidden;}
.parent{display: flex;flex-flow: column;}
.header{
height:100px;
background: #EB4C54;
}
.center{
flex: 1;
display: flex;
}
.center .lside{
width: 200px;
background: #2d3131;color: white;
}
.center .content{
flex: 1;
background: #f0f0f0;
overflow: auto;
}
.center .content .inner{
min-width: 700px;
min-height: 1000px;
}
.footer{
height: 50px;
background: #EB4C54;
}
</style>

详解:flex非常适合自适应布局,其实可以把定宽定高的设置全部删掉,或者百分比,整体布局也完全不会有问题。

兼容性:最低只能兼容到IE10。

gird解决方案

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<div class="parent">
<div class="header">header</div>
<div class="lside">lsidelsidelside</div>
<div class="content">
<div class="inner">
主内容区
</div>
</div>
<div class="footer">footer</div>
</div>
<style>
html,body,.parent{margin: 0;padding: 0;height: 100%;}
.parent{
display: grid;
grid-gap: 2px;
grid-template-columns: 20% auto;
grid-template-rows: 10% auto 5%;
overflow: hidden;
}
.parent div{background: lightsalmon;}
.header,.footer{grid-column: 1/4;}
.lside{
grid-column: 1;
word-wrap: break-word;
}
.content{
grid-column: 2/4;
overflow: auto;
}
.content .inner{
min-width: 500px;
min-height: 1000px;
}
</style>

详解:上述代码实现了一个栅格的全屏布局。关于gird布局的用法,详见本博客文章CSS Gird布局入门
兼容性:很差,IE完全不支持。

总结对比

方案 兼容 性能 自适应
Position 部分自适应
Flex 较差 可自适应
Grid 较好 可自适应

其它布局

全等四宫格布局

全等四宫格

两侧定宽,中间自适应布局

水平列表的底部对齐

学习资料

文章目录
  1. 1. 前戏:居中方案
    1. 1.1. 水平居中
      1. 1.1.1. inline-block + text- align
      2. 1.1.2. table + margin
      3. 1.1.3. absolute + transform
      4. 1.1.4. flex + justify-content
    2. 1.2. 垂直居中
      1. 1.2.1. table-cell + vertical-align
      2. 1.2.2. absolute + transform
      3. 1.2.3. flex + align-items
    3. 1.3. 水平 + 垂直居中
      1. 1.3.1. inline-block + text-align + table-cell + vertical-align
      2. 1.3.2. absolute + transform
      3. 1.3.3. flex + justify-content + align-items
    4. 1.4. 总结
  2. 2. 多列布局
    1. 2.1. 一列定宽,一列自适应布局
      1. 2.1.1. float + margin
      2. 2.1.2. float + margin (fix)
      3. 2.1.3. float + overflow
      4. 2.1.4. table布局
      5. 2.1.5. flex布局
    2. 2.2. 两列定宽,一列自适应
    3. 2.3. 一列不定宽加一列自适应
      1. 2.3.1. float + overflow
      2. 2.3.2. table布局
      3. 2.3.3. flex布局
    4. 2.4. 多列不定宽加一列自适应
    5. 2.5. 多列等分布局
      1. 2.5.1. 难点剖析
      2. 2.5.2. float
      3. 2.5.3. table布局
      4. 2.5.4. flex布局
    6. 2.6. 多列等高,其中一列宽度自适应
      1. 2.6.1. table布局
      2. 2.6.2. flex布局
      3. 2.6.3. float
  3. 3. 全屏布局
    1. 3.1. Position解决方案
    2. 3.2. flex解决方案
    3. 3.3. gird解决方案
    4. 3.4. 总结对比
  4. 4. 其它布局
    1. 4.1. 全等四宫格布局
    2. 4.2. 两侧定宽,中间自适应布局
    3. 4.3. 水平列表的底部对齐
  5. 5. 学习资料