前言

本系列文章主要针对了常用的几种css布局进行需求分析与要点详解,后续将不断对布局实现方案进行补充。本文主要介绍了水平居中、垂直居中和水平+垂直居中布局方案。

1.水平居中

首先分析最简单的水平居中,基本布局如下,两个div的嵌套。需要实现的是子div相对父div水平居中。

1
2
3
<div class="parent">
<div class="child"></div>
</div>

1.1 方案一

1
2
3
4
5
6
7
8
9
10
.parent{
width:100px;
height:100px;
text-align:center;
}
.child{
width:50px;
height:50px;
display:inline-block;
}

这个方案十分简单,MDN中的描述是,text-align控制行内内容如何相对它的块父元素对齐。

而将子div渲染成一个inline-block盒子可以保证它在父元素中的布局受text-align且能直接修改他的宽高属性。

优点:兼容性高,实现简单。

缺点:所有行内元素都会受text-align的影响而居中;且它是一个可继承的属性,若不想影响到更深层级的元素,需要在子元素中重新设置text-align属性。

1.2 方案二

1
2
3
4
5
6
7
8
9
.parent{
width:100px;
height:100px;
}
.child{
width:50px;
height:50px;
margin:0 auto;
}

这个方案也很简单,当左右外边距为auto时,会自动分配父元素剩余宽度均分到左右边距中。注意:此时子元素不能是行内元素,否则margin属性是不会生效的。

优点:兼容性高,实现简单。

缺点:没有很明显的缺点,如果要说,那就是如果子元素脱离了文档流,那么margin属性会失效。

1.3 方案三(不推荐)

1
2
3
4
5
6
7
8
9
10
11
12
.parent{
width:100px;
height:100px;
position:relative;
}
.child{
width:50px;
height:50px;
position:absolute;
left:50%;
transform:translateX(-50%);
}

或者

1
2
3
4
5
6
7
8
9
10
11
.parent{
width:100px;
height:100px;
}
.child{
width:50px;
height:50px;
position:relative;
left:50%;
transform:translateX(-50%);
}

这个方案较前面两个更为复杂,给人一种杀鸡焉用宰牛刀的感觉。强烈不推荐使用。

优点:没有明显的优点。

缺点:较复杂,使用相对布局和绝对布局反而会留下更大的隐患;transform属性兼容性不强。

1.4 方案四(flex/grid)

1
2
3
4
5
6
7
8
9
10
11
.parent{
width:100px;
height:100px;
display:flex;
/*display:grid;*/
justify-content:center;
}
.child{
width:50px;
height:50px;
}

父元素使用flexgrid)布局并设置主轴上(网格行轴)元素的排列方式为居中来实现水平居中,会带来一个问题就是主轴(网格行轴)上所有子元素都会居中。

优点:实现简单。

缺点:兼容性不强。

2.垂直居中

下面分析稍微复杂一些的垂直居中,基本布局同水平居中。需要实现的是子div相对父div垂直居中。

1
2
3
<div class="parent">
<div class="child"></div>
</div>

2.1 方案一

1
2
3
4
5
6
7
8
9
10
.parent{
width:100px;
height:100px;
display:table-cell;
vertical-align:middle;
}
.child{
width:50px;
height:50px;
}

根据MDN的描述,table-cell让一个元素表现为像<td>元素一样,也就是一个单元格。然后我们使用vertical-align属性来指定单元格内元素的垂直对齐方式。(这里涨姿势了,原来vertical-align不仅能用来指定行内元素(inline)也能用来指定表格单元格(table-cell)元素的垂直对齐方式。)

优点:兼容性比较好。

缺点:为了实现垂直居中效果而把父元素变成一个单元格,从语义上来看很不友好;vertical-align属性也是具有继承性,同上text-align

2.2 方案二

1
2
3
4
5
6
7
8
9
10
11
12
.parent{
width:100px;
height:100px;
position:relative;
}
.child{
width:50px;
height:50px;
position:absolute;
top:50%;
transform:translateY(-50%);
}

或者

1
2
3
4
5
6
7
8
9
10
11
.parent{
width:100px;
height:100px;
}
.child{
width:50px;
height:50px;
position:relative;
top:50%;
transform:translateY(-50%);
}

类似水平居中的方案二,也是比较常见的一种实现方式。

优点:没有明显的优点。

缺点:transform兼容性不强。需要使用相对布局和绝对布局实现。

2.3 方案三 (较推荐)

1
2
3
4
5
6
7
8
9
10
11
12
13
.parent{
width:100px;
height:100px;
position:relative;
}
.child{
width:50px;
height:50px;
position:absolute;
top:0;
bottom:0;
margin:auto 0;
}

具体解析我打算放到水平+垂直居中的方案三中去说,这里先吊个胃口。比起方案二,方案三没有了```transform``属性,兼容性更好。

优点:兼容性好。

缺点:需要使用相对布局和绝对布局实现。

2.4 方案四(flex/grid)

1
2
3
4
5
6
7
8
9
10
11
.parent{
width:100px;
height:100px;
display:flex;
/*display:grid;*/
align-items:center;
}
.child{
width:50px;
height:50px;
}

父元素使用flexgrid)布局并设置项目在其包含块中在交叉轴(块轴)上的对齐方式为居中,会带来一个问题就是交叉轴(块轴)上所有项目都会居中。

优点:实现简单。

缺点:兼容性不强。

3.水平+垂直居中

理论上,是不是把上面的水平居中和垂直居中全部排列组合一遍就可以得到NxM种方案?当然不是,这里也不浪费时间去做组合,直接给出一些可行的方案。同样,基本布局如下。需要实现的是子div相对父div水平+垂直居中。

3.1 方案一

1
2
3
4
5
6
7
8
9
10
11
.parent{
width:100px;
height:100px;
display:table-cell;
vertical-align:middle;
}
.child{
width:50px;
height:50px;
margin:0 auto;
}

该方案为水平居中方案一和垂直居中方案一的组合,也同样继承了它们的缺点和优点。同样的子元素不能是行内元素。

优点:兼容性好。

缺点:语义。

3.2 方案二

1
2
3
4
5
6
7
8
9
10
11
12
13
.parent{
width:100px;
height:100px;
position:relative;
}
.child{
width:50px;
height:50px;
position:absolute;
top:50%;
left:50%;
transform:translate(-50%,-50%);
}

或者

1
2
3
4
5
6
7
8
9
10
11
12
.parent{
width:100px;
height:100px;
}
.child{
width:50px;
height:50px;
position:relative;
top:50%;
left:50%;
transform:translate(-50%,-50%);
}

该方案为水平居中方案二和垂直居中方案二的组合。

优点:能用就行。

缺点:transform兼容性不强。需要使用相对布局和绝对布局实现。

3.3 方案三(推荐)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.parent{
width:100px;
height:100px;
position:relative;
}
.child{
width:50px;
height:50px;
position:absolute;
top:0;
bottom:0;
left:0;
right:0;
margin:auto;
}

这个方法并不是我原创的,而是在《CSS世界》中强烈推荐的一种方法。其核心就在于掌握格式化宽高的计算公式。

父元素的宽 = 子元素left + 子元素right + 子元素左右margin + 子元素左右border + 子元素左右padding + 子元素宽

父元素高 = 子元素top + 子元素bottom + 子元素上下margin + 子元素上下border + 子元素上下padding + 子元素高

因此,当子元素top/right/bottom/left、border、padding、宽高都确定时,margin:auto会将剩余父元素空间均分,达到居中的效果。

优点:兼容性好。

缺点:依然需要使用相对布局和绝对布局实现。

3.4 方案四(flex/grid)

1
2
3
4
5
6
7
8
9
10
11
12
.parent{
width:100px;
height:100px;
display:flex;
/*display:grid;*/
justify-content:center;
align-items:center;
}
.child{
width:50px;
height:50px;
}

这个方法综合了1.4和2.4,,会带来一个问题就是所有项目都会水平且垂直居中。

优点:实现简单。

缺点:兼容性不强。

后记

这些布局比较基础,但是依然有值得学习的思想。下文将对更加复杂也更加具有实际意义的几种布局进行分析。