CSS居中问题总结

目录

前言

  本篇集中对CSS中的各种居中问题进行总结。整体上需要居中的元素可以分为两大类-内联元素和块级元素,而居中方式又要考虑水平和垂直两个方向。


内联元素居中

水平居中


使用”text-align:center”

根据以下W3C的官方文档:

属性“text-align”用于描述块级元素中的行内内容如何布局。我们知道,块级元素的显示占据一整行,而行内元素可以在一行内并列显示,常用的行内元素有<img><input><label>等。默认地,块级元素中的行内元素是左对齐显示的,比如:

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>
<span>CSS行内元素居中测试</span>
</div>
</body>
</html>

效果如下图所示:

  这种情况下我们想对行内元素标签中的内容进行居中显示,则可以使用“text-align: center”。要注意的是,这个属性是用来决定行内元素的位置的,没错,但是该属性并不是写在行内元素上,而是要写在行内元素的父级元素,即块级元素这个“container”上,以此来决定内部文本的对齐方式。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#block-center {
text-align: center;
}
</style>

</head>
<body>
<div id="block-center">
<span>CSS行内元素居中测试</span>
</div>
</body>
</html>

效果如下图所示:

使用CSS3的flexbox”justify-content:center”

  和text-align一样的是,justify-content也适用于父类容器上,用于设置或检索弹性盒子元素在主轴(横轴)方向上的对齐方式。当属性值为“center”时,弹性盒子元素将向行中间位置对齐。该行的子元素将相互对齐并在行中居中对齐,同时第一个元素与行的主起始位置的边距等同于最后一个元素与行的主结束位置的边距(如果剩余空间是负数,则保持两端相等长度的溢出)。
代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#block-center {
display: flex; /*注意此处要指明flex布局*/
justify-content: center;
}
</style>

</head>
<body>
<div id="block-center">
<span>CSS行内元素居中测试(此处使用justify-content)</span>
</div>
</body>
</html>

效果如下图所示:

使用”display: table-cell”

  display: table的CSS声明能够让一个HTML元素和它的子节点像table元素一样。使用基于表格的CSS布局,使我们能够轻松定义一个单元格的边界、背景等样式,而不会产生因为使用了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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#block {
display: table;
width: 100%;
border: 1px solid black;
}
#block-center {
display: table-cell;
text-align: center;
border: 1px solid orangered;
}
#inline-1 {
height: 40px;
}
</style>

</head>
<body>
<div id="block">
<div id="block-center">
<img src="2.jpg" id="inline-1">
</div>
</div>
</body>
</html>

效果如下图所示:


垂直居中


默认情况

  对于上述已经水平居中的文本来说,相对于父级元素的垂直居中是默认的,不需要特殊声明,比如下面两张图,修改文本字号,它们始终处于父级div的垂直方向的中间(为了看得清楚,给父级元素加上了边框)。

行内元素互相之间的垂直居中

  如果一个父级元素中有多个行内元素,那么默认它们是在父元素的基线上进行对齐排列,也就是vertical-align: baseline;,以行内元素-图片为例,代码为:

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#block-center {
text-align: center;
border: 1px solid orangered;
}
#inline-1 {
height: 40px;
}
#inline-2 {
height: 60px;
}
</style>

</head>
<body>
<div id="block-center">
<img src="2.jpg" id="inline-1">
<img src="3.jpg" id="inline-2">
</div>
</body>
</html>

效果如下:

  此时如果不想让这些行内元素“底部对齐”呢,而是想让它们互相居中对齐,也就是图片的中线在同一条水平线上呢?那就要对行内元素本身使用vertical-align: middle;,代码为:

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#block-center {
text-align: center;
border: 1px solid orangered;
}
#inline-1 {
vertical-align: middle;
height: 40px;
}
#inline-2 {
vertical-align: middle;
height: 60px;
}
</style>

</head>
<body>
<div id="block-center">
<img src="2.jpg" id="inline-1">
<img src="3.jpg" id="inline-2">
</div>
</body>
</html>

效果如下图所示:


块级元素居中

水平居中


使用”margin: 0 auto”

  我们以最常见的块级元素-div为例,看一下居中的过程。首先创建一个div,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#block {
width: 100px;
height: 100px;
background-color: orangered;
}
</style>

</head>
<body>
<div id="block">
</div>
</body>
</html>

效果如下图所示:

  对块级元素本身添加margin: 0 auto可使其水平居中,即左右的外边距margin是auto的,会根据实际屏幕大小进行自动适配。修改上述style部分:

1
2
3
4
5
6
7
8
<style>
#block {
width: 100px;
height: 100px;
background-color: orangered;
margin: 0 auto;
}
</style>

效果如下图所示:

使用CSS3的flexbox”justify-content:center”

  justify-content:center不仅可以用来处理行内元素,也可以处理块级元素,为达到与上述方法相同的效果,代码为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#block {
display: flex;
justify-content: center;
}
#block-core {
width: 100px;
height: 100px;
background-color: orangered;
}
</style>

</head>
<body>
<div id="block">
<div id="block-core"></div>
</div>
</body>
</html>

效果图与上面的相同。

使用浮动配合相对定位

为了描述这种方法,我们通过下面的过程逐步深入分析:
1.考虑最简单的场景:父级div包含了子级div,代码如下:

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
html,body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
#wrapper {
border: 2px solid black;
}
#block {
width: 100px;
height: 100px;
background-color: orangered;
}
</style>

</head>
<body>
<div id="wrapper">
<div id="block">
</div>
</div>
</body>
</html>

易于理解,效果如下图所示:

2.上图黑色边框div是一个包裹元素,我们现在把它水平移动50%,也就是设置left属性。我们知道其默认的position属性为“static”,这种情况下left属性不起作用,因此将position改为relative,代码如下:

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
html,body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
#wrapper {
position: relative;
left: 50%;
border: 2px solid black;
}
#block {
width: 100px;
height: 100px;
background-color: orangered;
}
</style>

</head>
<body>
<div id="wrapper">
<div id="block">
</div>
</div>
</body>
</html>

效果如下图所示:

我们发现,此时<div id="wrapper">的左边界位于正中间,左右都是610px,也就是说,这个”left: 50%”是相对于wrapper的父级元素即body进行确定的,而body的宽度就是浏览器窗口宽度。同时发现,窗口出现了水平方向滚动条,这是由于wrapper向右进行偏移,但本身宽度又没变导致的水平方向溢出。溢出了多少呢?通过下面的操作容易看出溢出正好是浏览器宽度的一半,也就是wrapper向右偏移的距离:

3.为了防止出现滚动条,我们可以将wrapper这个div向左浮动,即加上一句“float: left;”,效果如下:

4.现在,想让橙色方块水平居中,只要加50%的left就好了,代码如下:

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
html,body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
#wrapper {
position: relative;
float: left;
left: 50%;
border: 2px solid black;
}
#block {
width: 100px;
height: 100px;
background-color: orangered;
position: relative;
left: -50%;
}
</style>

</head>
<body>
<div id="wrapper">
<div id="block">
</div>
</div>
</body>
</html>

效果如下:

使用”display:table-cell”

  这种方法我们将在下文中块级元素垂直居中统一介绍-使用”display:table-cell”同时达到水平和垂直居中的效果。


垂直居中


使用“top”属性和“margin-top”属性的结合

分析:
a. 由水平居中部分的分析我们可以知道,当元素水平居中后,在垂直方向还是“密铺”的,也就是从上到下排列,不会向下移动之类的。那么为了把元素“向下拽”,就考虑设置该元素的top属性为某个值,从而相对于父级元素在顶端有一定的空白,经过合理调整后可位于正中间。
b. 首先,我们要知道,css中position属性的默认值是static;其次,要知道top属性对于position值为“static”的元素不会产生任何效果。因此,想修改一个元素的top值,必须将元素的position修改为不是static的,这里我们改为“position: relative”。
c. 将top属性设置为一个百分比,这个百分比是相对于谁来说的呢?—是逐级向上寻找的,直到找到一个可以确定高度的父级元素,按照这个父级元素的高度结合百分比来设置top的具体值。这里橙色div的父级元素是<body>,再向上的父级元素是<html>。而浏览器在默认状态下,是没有给html和body一个高度的,为了使之成为刚才所说的“可以确定高度的父级元素”,将<body><html>的高度均设置为100%。
d. 既然是居中,也就是一半,我们考虑先将元素的top属性设置为50%,看看效果,代码为:

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
html,body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
#block {
position: relative;
width: 100px;
height: 100px;
background-color: orangered;
margin: 0 auto;
top: 50%;
}
</style>

</head>
<body>
<div id="block">
</div>
</body>
</html>

效果如下图所示:

e.从上图可以看出,橙色正方形的定边到浏览器窗口上方和下方的距离是一样的,都是298px,也就是说top: 50%;不是将元素居中,而是整体下移了父级元素高度的一半,这也是很好理解的。但是我们已经有了一个基础,在此基础上,通过再设置元素的margin-top,可以进行修正,margin-top是指元素的顶外边距,正值表明元素会继续下移,那么取负值即可向上,橙色正方形的高度为100px,那么margin-top取为-50px,css代码修改如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<style>
html,body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
#block {
position: relative;
width: 100px;
height: 100px;
background-color: orangered;
margin: 0 auto;
top: 50%;
margin-top: -50px;
}
</style>

效果如下图所示:

我们能够看出现在已经完全居中了。

使用CSS3“translateY”属性

  在上面方法的基础上,将下移50%的元素向上修正时,可以采取更简单的办法:translateY(-50%)。translateY()方法通过给定一个值,将元素沿Y轴进行移动,并且,给定的是是相对于元素自身的,因此50%就表示元素自身Y方向长度的一半。负号表示沿Y轴反方向移动(Y轴正向向下)。这种方法还有一个明显的好处,就是和margin-top相比,给定的是一个比例,而不像margin-top这样写死,这样后面的可维护性也会好一些。CSS代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<style>
html,body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
#block {
position: relative;
width: 100px;
height: 100px;
background-color: orangered;
margin: 0 auto;
top: 50%;
transform: translateY(-50%);
}
</style>

使用CSS3的flexbox”align-items: center”

  弹性盒模型在处理居中问题上真是简单明了。上面说了两种使用flexbox进行水平居中的方法,垂直居中一样可以使用flexbox搞定,align-items 属性定义flex子项在flex容器的纵轴方向上的对齐方式;justify-content属性定义flex子项在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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
html,body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
body {
display: flex;
align-items: center;
justify-content: center;
}
#block {
width: 100px;
height: 100px;
background-color: orangered;
}
</style>

</head>
<body>
<div id="block">
</div>
</body>
</html>

使用”display:table-cell”

  我们曾在内联元素的水平居中使用过这种办法,它也可以用于块级元素的水平和垂直居中。核心是使用”text-align: center; vertical-align: middle;”这两个属性。另外特别要注意的是,为了让这两个属性对于想要居中显示的块级元素生效,必须指定该块级元素为”display: inline-block;”。”display:inline-block”将对象呈递为内联对象,但是对象的内容作为块对象呈递。换句话说就是与”display: block”相比,它可以让设置了同类display属性的元素显示在同一行;与”display: inline”相比,可以对设置了该属性的元素设置高度。代码如下:

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
html,body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
#parent {
display: table;
width: 100%;
height: 100%;
}
#wrapper {
display: table-cell;
text-align: center;
vertical-align: middle;
}
#block {
width: 100px;
height: 100px;
background-color: orangered;
display: inline-block;
}
</style>

</head>
<body>
<div id="parent">
<div id="wrapper">
<div id="block">display: table-cell实现块级元素水平和垂直居中</div>
</div>
</div>
</body>
</html>

效果如下图所示:

使用CSS :before 选择器

  关于:before 选择器本身这里不做介绍,使用:before,在想要居中显示的元素前面追加了一个内联元素来占据相应的位置,从而达到垂直居中的效果,代码如下:

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
html,body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
body:before {
content:'';
display:inline-block;
vertical-align:middle;
height:50%;
}
#block {
width: 100px;
height: 100px;
background-color: orangered;
position: relative;
top: -50px;
}
</style>

</head>
<body>
<div id="block"></div>
</body>
</html>

效果如下图所示:


Bootstrap中关于居中的处理

  Bootstrap中关于排版的居中提供了两个class:

  1. class=”text-center”
    源码为:

    1
    2
    3
    .text-center {
    text-align: center;
    }
  2. class=”center-block”
    源码为:

    1
    2
    3
    4
    5
    .center-block {
    display: block;
    margin-right: auto;
    margin-left: auto;
    }

这两个类中使用到的方法在上文中都有提及。结合Bootstrap提供的其他强大的样式,容易实现各类排版。


小结

  本文总结了很多使用CSS对元素进行居中的办法,CSS是十分灵活且强大的,一定还有其他更好的办法。以上所列举的方法在正常开发中应该是够用了,并且通过实现居中理解了很多相关原理,这对于排错过程中快速定位问题很重要。