CSS水平垂直居中方案
Flexbox方案
Flexbox是最常用的方案,代码简洁而且兼容性非常好。
1 | .container { |
Grid方案
也能实现元素的水平垂直居中,不过兼容性不太好。
1 | .container { |
absolute + transform方案
通过绝对定位和transform实现水平垂直居中。
1 | .container { |
absolute + -margin方案
这个方案适合已知内容元素尺寸的情况。
其实这个方案跟上面的absolute + transform方案是类似的,但是margin为百分比的时候,是相对于父元素的宽度来计算的(无论margin-top还是margin-left都是相对于父元素的宽度,这个CSS规范是有点特别的,因为直觉会认为取值为百分比的情况下,margin-top就是相对于父元素的高度,margin-left就是相对于父元素的宽度),所以不能用百分比。
1 | .container { |
表格布局方案
通过display: table
和display: tble-cell
实现居中,利用了表格布局中display: table-cell
的元素设置了vertical-align: middle
会在垂直方向上居中的特性,然后设置text-align: center
之后文字就会居中。这里会有个问题是,如果content中的元素不占满整行的,可能在水平方向上会不居中。
1 | .container { |
line-height + text-align方案
这种方案只适合单行文本或内联元素的居中。
1 | // 父元素设置line-height与容器高度一样 |
margin: auto方案
适用于已知子元素尺寸且容器为块级元素的情况。
1 | .container { |
这里想解释一下为什么如果仅仅设置了子元素margin: auto
是无法实现水平垂直居中的,因为我们都知道给元素设置margin: 0 auto
可以实现水平方向的居中,可能会误以为元素设置margin: auto
可以实现水平垂直居中。
当父元素是普通的块级元素的时候,子元素的margin: auto
仅在水平方向有效,浏览器会计算父元素的剩余水平空间,并将其平均分配给子元素的左右外边距,实现水平居中。在普通文档流中,垂直方向没有类似水平方向margin: auto
的自动分配机制,垂直方向的外边距会被浏览器解析为0,会被浏览器忽略,所以普通文档流没有自动分配垂直剩余空间的机制,通过margin实现垂直居中。
具体原因是水平方向块级元素默认占满父元素,如果子元素设置固定宽度,浏览器可以计算水平剩余空间,并通过margin: auto分配剩余空间到左右边距,实现水平居中。
垂直方向块级元素高度默认由内容撑开,父元素高度通常不固定。即使父元素显示地设置height,有固定的高度,浏览器也不会将垂直剩余空间分配给margin: auto,因为规范未定义此行为。
但是当父元素设置了display: flex
,触发了Flex上下文,子元素成为Flex容器的Flex Item, 创建了一个新的布局上下文,此时margin: auto
的行为被重新定义,Flex容器会将剩余空间(父元素宽高 - 子元素宽高)平均分配给子元素的四个方向的外边距,从而实现水平垂直居中。
absolute + margin: auto方案
一个注意的地方是子元素必须设置固定的宽高。
1 | .container { |
这个方案的原理是:
拉伸子元素
left: 0; top: 0; right: 0; bottom: 0
将子元素拉伸至与父容器四边对齐,此时这时候子元素尺寸被隐式固定,子元素的尺寸等于父容器尺寸。如果没有设置这些值,元素的默认位置是在父元素的左上角,此时即使子元素有固定的宽高,浏览器也无法正确计算剩余空间,因为子元素的定位未与父容器边界关联,导致margin: auto
在无效。固定子元素尺寸
显式设置子元素的 width 和 height(如 200x200px),此时父容器与子元素之间会产生明确的剩余空间。
margin: auto
分配剩余空间
这时候浏览器能明确计算出水平和垂直方向的剩余空间,将剩余空间均分到子元素的四个外边距,实现居中。
CSS规范规定,绝对定位元素的margin: auto
在明确剩余空间时,可以分配四个方向的外边距。这是绝对定位的布局机制决定的,允许显式控制剩余空间。
其实left: 0; top: 0; right: 0; bottom: 0
这个设置只要设置left和right相等,top和bottom相等就可以了。
水平剩余空间 = 400px - 0px - 0px - 200px = 200px
margin-left = margin-right = 剩余空间 / 2 = 200px / 2 = 100px
这里有一个有趣的地方是,如果CSS按照以下配置:
1 | .container { |
那么.content元素距离父元素右侧的距离是多少?答案是180px。
这是因为当同时设置 width 、 left 和 right 时, right 属性的实际效果会被忽略。浏览器会优先考虑 left 和 width 的值,然后根据容器宽度自动计算出右侧的实际距离。
如果想要 right: 20px 生效,需要去掉 width 属性,这样元素的宽度会自动适应剩余空间。
当剩余空间大于等于0的时候,浏览器通过均分剩余空间的外边距实现居中。
当剩余空间小于0的时候,浏览器不再分配负外边距,而是优先遵循left/top的定位值,无法居中。
1 | .container { |
以上代码,垂直方向能居中,水平方向不能居中,距离左边50px。