面试题:水平垂直居中的17种方法
[1]网友一丝说:flex 是 2012 年的语法,是以后的标准box 是 2009 年的语法,已经过时,需要加上对应前缀 123123 .father { display: -webkit-box; -webkit-box-pack: center; -webkit-box-align: center;}table-cell + text-align 123123
[1]网友一丝说:flex 是 2012 年的语法,是以后的标准box 是 2009 年的语法,已经过时,需要加上对应前缀
面试的时候,绝不能只说一种,绝不能说一种解决方案,绝不能停下你吞吞吐吐的嘴 CSS 方面问的最多的问题之一,我想分三种情况,水平居中、垂直居中和水平垂直居中来分析 单单就水平垂直居中而言,大概有以下几种方案: 居中元素不定宽高 仅居中元素定宽高适用: 局限性较大的全局居中 需设置 display: inline-block 行内块元素 脱离文档流 这里说明下,width:100px 必须是具体的数字,且这个居中是外层居中,宽度中的内容没有居中 与水平方向的居中一样,都是脱离文档流的做法 display: table-cell ,让其标签元素以表格单元格的形式呈现,类似于 td 标签, vertical-align: middle,用来指定行内元素(inline)或表格单元格(table-cell)元素的垂直居中 grid 和 flex 很像,是 flex 的升级版,所以 grid 能做的事情更多 以上绝对定位、flex、grid 关于水平垂直居中的做法,剩下再说居中比较老的布局方法 这是一个已经过时的布局,可以看看这篇文章 CSS3 display: flex 和 display: box 有什么区别?[1] 网友一丝说: flex 是 2012 年的语法,是以后的标准 box 是 2009 年的语法,已经过时,需要加上对应前缀 line-height 与 height ,行高和高度一样高,自然就垂直方向居中了 这个很冷闷,有人介绍过这种情况[2] table 标签自己将它垂直居中了,text-align:center 后就是水平居中了 可以看 demo[3] 当元素有宽高的情况,又多了三种方案 父元素必须要有个高度,这样才能撑开容器。子元素必须要有个宽高,才能计算出 margin 值 与 margin 负边距一个道理,父元素需要设置一个高度。子元素必须要有高度,不用 margin,而用 CSS3 中的 calc,计算出要居中位移,兼容性需要支持 CSS3 属性 同以上两种情况。 这三种需要定位方式来实现水平垂直居中的方法,需要设置父元素的高度(一定要有,撑开画面),子元素需要设置宽高,前两种方法是为了算出它在父元素中的相对位置,后一种方法是为了说明子元素是个容器(如果不设置宽高,就是无) 其实,水平垂直居中方面,如果面试官硬要问还有吗?还真的有,用 fixed 定位。但这个方法有缺陷,虽然能实现水平垂直居中,但它是相对于视口(viewport),而非父元素 方法就是以上用 absolute 实现的改成 fixed 即可 •须知宽高 + fixed + transform•须知宽高 + fixed + 负 margin•须知宽高 + fixed + calc•须知宽高 + fixed + margin auto 这四种方法,都需要设置子元素的宽高 这里贴一下代码 随着微软宣布放弃 IE11,现实项目中完全可以使用 flex 布局,grid 部分还不适配,但是以后肯定会取代 flex。 虽然写了很多,但是自己工作中也不会使用 table 、writing-mode、-webkit-box 等过时的布局方式,写这篇文章,纯粹是为了面试时被问到这种问题。 收获是 absolute 的居中要父子同心(父元素设置高度,子元素设置宽高),fixed 的居中只需要设置子元素的宽高。 线上 demo[4] 查看 •如何居中一个元素(终结版)[5]•给你一份详细的 CSS 布局指南,请查收[6]•CSS 实现水平垂直居中的 1010 种方式(史上最全)[7] [1] CSS3 display: flex 和 display: box 有什么区别?: https://www.zhihu.com/question/22991944水平居中
text-align: center
text-align: center;
绝对定位 + transform 位移
position: absolute;left: 50%;transform: translateX(-50%);
宽度+ margin: 0 auto
width: 100px;margin: 0 auto;
垂直居中
绝对定位 + transform 位移
position: absolute;top: 50%;transform: translateY(-50%);
table-cell + vertical-align
display: table-cell;vertical-align: middle;
水平垂直居中
绝对居中 + transform 位移
<div class="father"> <div class="son"> 123123 </div></div>
.father { position: relative;}.son { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);}
flex 属性居中
<div class="father"> <div class="son"> 123123 </div></div>
.father { display: flex; justify-content: center; align-items: center;}
flex + margin auto
<div class="father"> <div class="son"> 123123 </div></div>
.father { display: flex;}.son { margin: auto;}
grid 属性居中
<div class="father">123123</div>// 或者<div class="father"> <div class="son"> 123123 </div></div>
.father { display: grid; justify-content: center; align-items: center;}
grid 子项属性居中
<div class="father"> <div class="son"> 123123 </div></div>
.father { display: grid;}.son { align-self: center; justify-self: center;}
grid + margin auto
<div class="father"> <div class="son"> 123123 </div></div>
.father { display: grid;}.son { margin: auto;}
-webkit-box 属性居中
<div class="father"> <div class="son"> 123123 </div></div>
.father { display: -webkit-box; -webkit-box-pack: center; -webkit-box-align: center;}
table-cell + text-align
<div class="father"> <div class="son"> 123123 </div></div>
.father { display: table-cell; vertical-align: middle; text-align: center;}.son { display: inline-block;}
line-height + text-align
<div class="father"> <div class="son"> 123123 </div></div>
.father { height: 200px; line-height: 200px; text-align: center;}
writing-mode
<div class="father"> <div class="“son”"> <div class="“sonson”"> 123123 </div> </div></div>
.father { writing-mode: tb-lr; writing-mode: vertical-lr; text-align: center;}.father .son { writing-mode: lr-tb; writing-mode: horizontal-tb; text-align: center; width: 100%; display: inline-block;}.father9 .son .sonson { display: inline-block; text-align: initial;}
table
<table> <tbody> <tr> <td class="father"> <div class="son"> 123123 </div> </td> </tr> </tbody></table>
.father { text-align: center;}
须知宽高 + 绝对居中 + margin 负边距
<div class="father"> <div class="son"> 123123 </div></div>
.father { position: relative; height: 200px;}.son { width: 100px; height: 100px; position: absolute; top: 50%; left: 50%; margin: -50px 0 0 -50px;}
须知宽高 + 绝对定位 + calc
<div class="father"> <div class="son"> 123123 </div></div>
.father { position: relative; height: 200px;}.son { width: 100px; height: 100px; position: absolute; top: calc(50% - 50px); left: calc(50% - 50px);}
须知宽高 + 绝对居中 + margin: auto
<div class="father"> <div class="son"> 123123 </div></div>
.father { position: relative; height: 300px;}.son { width: 100px; height: 100px; position: absolute; top: 0; left: 0; right: 0; bottom: 0; margin: auto;}
其他方法
<div class="father"> <div class="son"> 123123 </div></div>
/* transform */.son { width: 100px; height: 100px; position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: blue;}/* 负 margin */.son { width: 100px; height: 100px; position: fixed; top: 50%; left: 50%; margin-left: -50px; margin-top: -50px; background: blue;}/* calc */.son { width: 100px; height: 100px; position: fixed; top: calc(50% - 50px); left: calc(50% - 50px); background: blue;}/* margin: auto */.son { width: 100px; height: 100px; position: fixed; top: 0; left: 0; bottom: 0; right: 0; margin: auto; background: blue;}
总结
参考资料
References
[2] 这种情况: https://liyongleihf2006.github.io/center-box/
[3] demo: https://codepen.io/jojobo/pen/ExvWPbP
[4] demo: https://azhubaby.com/demo/水平垂直居中.html
[5] 如何居中一个元素(终结版): https://github.com/ljianshu/Blog/issues/29
[6] 给你一份详细的 CSS 布局指南,请查收: https://juejin.cn/post/6844904121862979597#heading-2
[7] CSS 实现水平垂直居中的 1010 种方式(史上最全): https://yanhaijing.com/css/2018/01/17/horizontal-vertical-center/