本文译自https://css-tricks.com/centering-css-complete-guide/ , 讲述了如何利用 css 来实现常见的水平和垂直居中。
人们一直都在抱怨CSS的设计者们,为什么一定要把一个简简单单的居中设计的如此困难。但我认为居中问题并不在于有多难,而是在于居中的使用场景非常多,对应到每种场景下的使用方法也因此各不相同。
那么接下来让我们来制作一个决策树,用来讲清楚什么情况下你应该使用什么方法来实现居中。希望它能有所帮助。
一. 水平居中 1. 行内元素或inline-*元素的居中(比如文本或链接) 如果它的父级是块状元素,你可以很容易的通过以下代码实现:
1 2 3 .center-children { text-align : center; }
这种方法对 inline、inline-block、inline-table、inline-flex元素有效
2. 单个块状元素的居中 可以通过把它的margin-left和margin-right值都设置为auto来实现(前提是它已经设置好了width宽度,否则元素宽度就是100%,居中也就没有意义了)。代码如下:
1 2 3 .center-me { margin : 0 auto; }
这种方法无需关心子元素及父级元素的宽度
3. 多个块状元素的居中 如果你想让多个块状元素在同一行居中,那么你最好改变他们的display属性。display:inline-block以及display:flex都可以做到这一点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <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 >
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 body { background : #f06d06 ; font-size : 80% ; } main { background : white; margin : 20px 0 ; padding : 10px ; } main div { background : black; color : white; padding : 15px ; max-width : 125px ; margin : 5px ; } .inline-block-center { text-align : center; } .inline-block-center div { display : inline-block; text-align : left; } .flex-center { display : flex; justify-content : center; }
上述方法不适合这几个块状元素是垂直排列的时候,这种情况下把margin值设置为auto的方式依然是好使的。
二. 垂直居中 在css中,垂直居中比水平居中需要更多的技巧。
1. 行内元素或inline-*元素的居中(比如文本或链接) 单行 有时候行内元素或文字看起来垂直居中,其实仅仅是因为他们的上下内边距相等。
1 2 3 4 .link { padding-top : 30px ; padding-bottom : 30px ; }
如果padding值不作为垂直居中的一个选项的话,同时你又想让一些不会折行的文字垂直剧中的话,让元素的line-height等于它的高度就可以了。
1 2 3 4 5 <main > <div > I'm a centered line. </div > </main >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 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; }
多行 设置相等的上下内边距同样也可以使多行文本垂直居中,但是如果这个不起作用的话,你可以把文本所在的元素换为table cell,或自由或强制的使之表现的像一个table元素。此时vertical-align属性就可以起作用了,它与我们通常所做的在行上处理元素对齐的方式不同
1 2 3 4 5 6 7 8 9 10 11 12 <table > <tr > <td > I'm vertically centered multiple lines of text in a real table cell. </td > </tr > </table > <div class ="center-table" > <p > I'm vertically centered multiple lines of text in a CSS-created table layout.</p > </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 table td { background : black; color : white; padding : 20px ; border : 10px solid white; } .center-table { display : table; height : 250px ; background : white; width : 240px ; margin : 20px ; } .center-table p { display : table-cell; margin : 0 ; background : black; color : white; padding : 20px ; border : 10px solid white; vertical-align : middle; }
如果你觉得这种方法过时了,或许你可以尝试下flexbox布局。这种方法会非常简单。
1 2 3 <div class ="flex-center" > <p > I'm vertically centered multiple lines of text in a flexbox container.</p > </div >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 .flex-center { background : black; color : white; border : 10px solid white; display : flex; flex-direction : column; justify-content : center; height : 200px ; resize : vertical; overflow : auto; } .flex-center p { margin : 0 ; padding : 20px ; }
请注意上面这种方法只在父级元素有固定高度的时候起作用那个。
如果你觉得以上两种方法都过时了,你可以试试伪元素。在伪元素撑满整个父级的时候,当前元素因为设置了vertical-align:Center而对齐。 (译者备注:这儿的伪元素before其实只是为了定下基线。before伪元素和需居中的元素都设置了display:inline-block,这样,他们的基线会对齐到同一行,又设置vertical-align:center,基线变为居中对齐,因此达到目标)
1 2 3 4 <div class ="ghost-center" > <p > I'm vertically centered multiple lines of text in a container. Centered with a ghost pseudo element</p > </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 30 31 32 33 34 35 body { background : #f06d06 ; font-size : 80% ; } div { background : white; width : 240px ; height : 200px ; margin : 20px ; color : white; resize : vertical; overflow : auto; padding : 20px ; } .ghost-center { position : relative; } .ghost-center ::before { content : " " ; display : inline-block; height : 100% ; width : 1% ; vertical-align : middle; } .ghost-center p { display : inline-block; vertical-align : middle; width : 190px ; margin : 0 ; padding : 20px ; background : black; }
2. 块状元素的居中 已知元素的高度 很多情况下我们是不知道页面布局的高度的,有很多原因:如果宽度改变,文档流会改变对应的高度。文档样式的改变,文档树木的改变同样也会改变高度。有固定宽高比的元素,例如image元素,在resize的时候高度也会随之调整。
但是你确实知道居中元素高度的话,你可以使用如下方法进行居中。
1 2 3 4 5 6 7 8 9 .parent { position : relative; } .child { position : absolute; top : 50% ; height : 100px ; margin-top : -50px ; }
元素高度未知 仍然可以做到居中,你可以用 transform 属性,用 translate 设置 -50%(它以元素当前的宽和高为基础)
1 2 3 4 5 6 7 8 .parent { position : relative; } .child { position : absolute; top : 50% ; transform : translateY (-50%); }
可以实用flexbox 使用flexbox进行垂直居中就简单多了。
1 2 3 4 5 .parent { display : flex; flex-direction : column; justify-content : center; }
(译者注 : 这也就意味着,在低版本浏览器里面,对于高度不固定的元素,垂直居中基本上是做不到的)
三. 水平垂直居中 你可以把上面提到的技术结合起来来达到效果。但是我发现总体来说会有三种情况:
1.元素的宽高固定 设定父级容器为相对定位的容器,设定子元素绝对定位的位置 position: absolute; top: 50%; left: 50%,最后使用负向 margin 实现水平和垂直居中,margin 的值为宽高(具体的宽高需要根据实际情况计算 padding)的一半
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 .parent { position : relative; } .child { width : 300px ; height : 100px ; padding : 20px ; position : absolute; top : 50% ; left : 50% ; margin : -70px 0 0 -170px ; }
2.宽高不固定 如果你不知道它的宽高,你可以使用transform属性,并把它的translate值设为-50%。
1 2 3 4 5 6 7 8 9 .parent { position : relative; } .child { position : absolute; top : 50% ; left : 50% ; transform : translate (-50%, -50%); }
3.可以使用flexbox 1 2 3 4 5 6 7 8 <main > <div > I'm a block-level-ish element of an unknown width and height, centered vertically within my parent. </div > </main >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 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; }
4. 1 2 3 4 5 6 7 8 9 10 11 .dad { position : relative; } .son { position : absolute; margin : auto; top : 0 ; right : 0 ; bottom : 0 ; left : 0 ; }