原文:Centering in CSS: A Complete Guide
在CSS中居中是(开发者)抱怨CSS设计的代表问题之一。有人嘲笑说:这有什么困难的呢?我认为,难度不在于解决问题,而在于有如此多的不同解决方法。这些方法在不同的场景下有不同的用处。这让我们手足无措。
让我用一个决策树来帮助我们选择合适的解决方案。
1 水平居中(Horizontally)
1.1居中的对象是一个inline或者inline-* 元素(像text或者links)
你能在一个block-level父元素内水平居中一个inline(或者inline-*)元素,像下面这样:
.center-children {
text-align: center;
}
HTML:
<div class="center-children">
<span>love js</span>
</div>
这个方法适用于inline, inline-block, inline-table, inline-flex的元素
1.2 居中的对象是一个block-level元素
你能够居中一个block-level元素,通过给(子元素)margin-left和margin-right属性设置auto值。前提是这个元素有一个设定的宽度,否则它会和父元素等宽,从而不会被居中。代码如下:
.center-me {
margin: 0 auto;
}
HTML:
<div>
<div style="width:20%;" class="center-me">love js</div>
</div>
无论你想居中的block-level元素及其父元素的宽度是多少,这个方法都会起作用
1.3 如果有超过一个的block-level元素
如果你有两个或者更多的block-level元素需要在一行中水平居中,有可能更好的方法的是改变它们的display值。以下示例代码两种方式:1,设置display的值为inline-block像1.1一样居中;2,flex布局,不要忘记设置flex-direction的值
.inline-block-center {
text-align: center;
}
.inline-block-center div {
display: inline-block;
text-align: left;
}
.flex-center {
display: flex;
justify-content: center;
}
main div {
max-width: 125px;
}
<main class="inline-block-center">
<div>
I'm an element that is block-like with my siblings and we're centered in a row.
</div>
<div>
I'm an element that is block-like with my siblings and we're centered in a row. I have more content in me than my siblings do.
</div>
<div>
I'm an element that is block-like with my siblings and we're centered in a row.
</div>
</main>
<main class="flex-center">
<div>
I'm an element that is block-like with my siblings and we're centered in a row.
</div>
<div>
I'm an element that is block-like with my siblings and we're centered in a row. I have more content in me than my siblings do.
</div>
<div>
I'm an element that is block-like with my siblings and we're centered in a row.
</div>
</main>
除非你的意思是:你有多个block-level元素互相堆叠起来,那么auto margin的技巧仍然是合适的。
2 垂直居中
在CSS中垂直居中需要那么一点点技巧。
2.1 垂直居中的对象是否是一个inline-*元素(比如text或者link)?
2.1.1 单行
有时候inline/text元素能够看起来像是垂直居中,只是因为在它们上面和下面有一个padding:
.link {
padding-top: 30px;
padding-bottom: 30px;
}
示例代码:
<main>
<a href="#0">We're</a>
<a href="#0">Centered</a>
<a href="#0">Bits of</a>
<a href="#0">Text</a>
</main>
body {
background: #f06d06;
font-size: 80%;
}
main {
background: white;
margin: 20px 0;
padding: 50px;
}
main a {
background: black;
color: white;
padding: 40px 30px;
text-decoration: none;
}
如果因为某种原因,padding不是你的选择,而且你正在尝试居中某段你知道不会被包装的文本。那么有一个居中文本的技巧:让line-height的值等于height的值:
.center-text-trick {
height: 100px;
line-height: 100px;
white-space: nowrap;
}
示例代码:
HTML
<main>
<main>
<div>
I'm a centered line.
</div>
</main>
</main>
CSS:
body {
background: #f06d06;
font-size: 80%;
}
main {
background: white;
margin: 20px 0;
padding: 40px;
}
main div {
background: black;
color: white;
height: 100px;
line-height: 100px;
padding: 20px;
width: 50%;
white-space: nowrap;
/*与normal的不同在于不换行*/
}
2.1.2 多行
在顶部和底部设置相等padding也能给多行文本设置居中效果。
flex布局对于垂直居中多行文本仍然是起作用的。
2.2 垂直居中一个block-level元素
2.2.1 是否知道元素的高度
在网页布局中,不知道高度是相当普遍的。这出于很多原因:如果宽度改变了,文本流会改变高度; 文本样式的变化也会改变高度。文本数量的变化也会改变高度;有一个固定比例的元素,比如图像,会在resize的时候改变高度;等等。
但是如果你知道高度,你可以向这样垂直居中
.parent {
position: relative;
}
.child {
position: absolute;
top: 50%;
height: 100px;
margin-top: -50px; /* account for padding and border if not using box-sizing: border-box; */
}
示例代码:
<main>
<div>
I'm a block-level element with a fixed height, centered vertically within my parent.
</div>
</main>
body {
background: #f06d06;
font-size: 80%;
}
main {
background: white;
height: 300px;
margin: 20px;
width: 300px;
position: relative;
resize: vertical;
overflow: auto;
}
main div {
position: absolute;
top: 50%;
left: 20px;
right: 20px;
height: 100px;
margin-top: -70px;
background: black;
color: white;
padding: 20px;
}
2.2.2 不知道高度
在top:50%下拉子元素后,将它向上轻推50%,这也有可能居中子元素。
.parent {
position: relative;
}
.child {
position: absolute;
top: 50%;
transform: translateY(-50%);
}
2.2.3 如果能使用flex布局
毫无疑问,使用flexbox是很简单的
.parent {
display: flex;
flex-direction: column;
justify-content: center;
}
示例代码
<main>
<div>
I'm a block-level element with an unknown height, centered vertically within my parent.
</div>
</main>
body {
background: #f06d06;
font-size: 80%;
}
main {
background: white;
height: 300px;
width: 200px;
padding: 20px;
margin: 20px;
display: flex;
flex-direction: column;
justify-content: center;
resize: vertical;
overflow: auto;
}
main div {
background: black;
color: white;
padding: 20px;
resize: vertical;
overflow: auto;
}
3垂直和水平同时居中
你可以结合上述技巧,从而得到完美居中的元素。主要可以分为3种情况:
3.1 元素是否是固定宽度和高度
在你使用50%/50%的绝对布局后,使用负的外边距等于一半高度和高度可以达到目的,这有很好的浏览器件兼容性。
.parent {
position: relative;
}
.child {
width: 300px;
height: 100px;
padding: 20px;
position: absolute;
top: 50%;
left: 50%;
margin: -70px 0 0 -170px;
}
示例代码:
<main>
<div>
I'm a block-level element a fixed height and width, centered vertically within my parent.
</div>
</main>
body {
background: #f06d06;
font-size: 80%;
padding: 20px;
}
main {
position: relative;
background: white;
height: 200px;
width: 60%;
margin: 0 auto;
padding: 20px;
resize: both;
overflow: auto;
}
main div {
background: black;
color: white;
width: 200px;
height: 100px;
margin: -70px 0 0 -120px;
position: absolute;
top: 50%;
left: 50%;
padding: 20px;
}
3.2 不知道宽高
如果你不知道宽高,你可以使用tranforms属性,在水平和垂直两个方向使用一个负的50%translate
.parent {
position: relative;
}
.child {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
示例代码
<main>
<div>
I'm a block-level element of an unknown height and width, centered vertically within my parent.
</div>
</main>
body {
background: #f06d06;
font-size: 80%;
padding: 20px;
}
main {
position: relative;
background: white;
height: 200px;
width: 60%;
margin: 0 auto;
padding: 20px;
resize: both;
overflow: auto;
}
main div {
background: black;
color: white;
width: 50%;
transform: translate(-50%, -50%);
position: absolute;
top: 50%;
left: 50%;
padding: 20px;
resize: both;
overflow: auto;
}
3.3 如果能使用flexbox
为了在两个方向上居中,你需要使用两个居中属性
.parent {
display: flex;
justify-content: center;
align-items: center;
}
示例代码
<main>
<div>
I'm a block-level-ish element of an unknown width and height, centered vertically within my parent.
</div>
</main>
body {
background: #f06d06;
font-size: 80%;
padding: 20px;
}
main {
background: white;
height: 200px;
width: 60%;
margin: 0 auto;
padding: 20px;
display: flex;
justify-content: center;
align-items: center;
resize: both;
overflow: auto;
}
main div {
background: black;
color: white;
width: 50%;
padding: 20px;
resize: both;
overflow: auto;
}
3.4 如果能使用grid
(grid布局)这个小技巧对于(垂直水平居中)一个元素很有效
body, html {
height: 100%;
display: grid;
}
span { /* thing to center */
margin: auto;
}
示例代码
<span>
I'm centered!
</span>
body, html {
height: 100%;
display: grid;
}
span {
margin: auto;
}
4 小结:
我们完全可以用CSS实现花式居中。