突然顿悟了“书读百遍,其义自现。”当然,还需要配合“好记性不如烂笔头”,整理总结一下常见的元素水平垂直居中的方法。
起因是有童鞋问我让元素垂直居中的方法,我突然懵了,居然一时没有描述出来,吓得赶紧抽空总结了一下,最后引出了元素水平且垂直居中。
方法一
最常用的方法:父元素 position: relative; 元素自身 position: absolute; top: 0; bottom: 0; margin: auto;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <style> .outer { width: 500px; height: 500px; background-color: #000; position: relative; }
.inner { width: 100px; height: 100px; background-color: #f00; position: absolute; top: 0; bottom: 0; margin: auto; } </style>
<div class="outer"> <div class="inner"></div> </div>
|
margin: auto;
很重要,只有设置了它,浏览器才会自动分配可用空间,根据规范的描述,如果“margin-top”和“margin-bottom”都是 auto,则在额外约束下,让两边得到相等的值;
其实大家都知道,这种方法通常是用来设置元素绝对居中
(也就是水平垂直居中)的,规范的描述同样适用于“margin-left”和“margin-right”,所以可以达到元素绝对居中的作用,如下 👇:
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
| <style> .outer { width: 500px; height: 500px; background-color: #000; position: relative; }
.inner { width: 100px; height: 100px; background-color: #f00; position: absolute; top: 0; bottom: 0; right: 0; left: 0; margin: auto; } </style>
<div class="outer"> <div class="inner"></div> </div>
|
再来聊聊margin: auto;
这个神奇的属性,通常情况下,让一个元素水平居中很简单margin: 0 auto;
,而如果要让一个元素垂直居中,则需要很多的步骤,为什么?
因为浏览器的宽度是有限的,从一开始就知道父元素的宽度,然后margin: 0 auto;
来分配父元素 X 轴上的可用空间,想想也很合理;
虽然浏览器的高度也是有限的,但内容的高度却是未知的,像现在的流式布局,一直滚动一直有内容,所以很难确定父元素 Y 轴到底有多长,那么margin: auto;
就无法分配父元素 Y 轴上的可用空间,居中就更无从谈起了;
有人抬杠说, X 轴上的内容也可以是无限的呀,对,你说的对,反正我没见过哪家公司的站点还有横向滚动条的(特殊需求除外);
那么这里的绝对定位就好理解了:因为要分配父元素的可用空间,当然要知道父元素的边界了,所以首先父元素position: relative;
,然后元素自身position: absolute;
,接着定义所有边界top: 0; right: 0; bottom: 0; left: 0;
,既然距离所有边界的距离都是一样的,那margin: auto;
就只能给轴的两边分配相同的值,绝对居中也就成了;
方法二
也是常用方法的一种:父元素 position: relative; 元素自身 position: absolute; margin-top: -(元素自身高度的一半);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <style> .outer { width: 500px; height: 500px; background-color: #000; position: relative; }
.inner { width: 100px; height: 100px; background-color: #f00; position: absolute; top: 50%; margin-top: -50px; } </style>
<div class="outer"> <div class="inner"></div> </div>
|
绝对定位相对于最近的且 position 不是 static 的父元素,而且,定位原点位于父元素内容区域(content)的左上角,但也有例外,如果设置了left: 0; 和 top: 0;
,那么,定位原点则位于父元素的实际占用区域(content + padding)的左上角,不过,这种情况并不多见;
这里的top: 50%;
让元素左上角位于父元素高度一半的位置,这里是父元素高度的中心点,但元素自身是有高度的,所以还需要让元素再向上移动自身高度的一半margin-top: -50px;
,来达到居中的目的;
那元素绝对居中则很简单了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <style> .outer { width: 500px; height: 500px; background-color: #000; position: relative; }
.inner { width: 100px; height: 100px; background-color: #f00; position: absolute; top: 50%; margin-top: -50px; left: 50%; margin-left: -50px; } </style>
<div class="outer"> <div class="inner"></div> </div>
|
方法三
还是最常用的方法之一:父元素 position: relative; 元素自身 position: absolute; transform: translateY(-50%);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <style> .outer { width: 500px; height: 500px; background-color: #000; position: relative; }
.inner { width: 100px; height: 100px; background-color: #f00; position: absolute; top: 50%; transform: translateY(-50%); } </style>
<div class="outer"> <div class="inner"></div> </div>
|
与上一种方法大同小异,让元素左上角位于父元素高度一半的位置,然后让元素在 Y 轴上向上移动自身高度的一半;
既然能在 Y 轴上移动,当然也可以在 X 轴上移动,所以绝对居中如下 👇:
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
| <style> .outer { width: 500px; height: 500px; background-color: #000; position: relative; }
.inner { width: 100px; height: 100px; background-color: #f00; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
} </style>
<div class="outer"> <div class="inner"></div> </div>
|
需要注意的是,transform 属性只能设置一次,后面设置的会自动覆盖前面的,所以需要使用组合属性translate(-50%, -50%);
且需要设置两个值,不能像 margin 或 padding 一样省略其他值,当然,也可以使用translate3d(-50%, -50%, 0);
,看起来高大上,但没有实际意义;
方法四
日常很少使用,由方法三演变而来元素自身 position: relative; top: 50%; transform: translateY(-50%);
;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <style> .outer { width: 500px; height: 500px; background-color: #000; }
.inner { width: 100px; height: 100px; background-color: #f00; position: relative; top: 50%; transform: translateY(-50%); } </style>
<div class="outer"> <div class="inner"></div> </div>
|
咦,position: absolute;
还能理解,毕竟父元素设置了position: relative;
,所以相对于父元素定位,给自身设置position: relative;
是什么鬼?那么它相对于什么定位?top: 50%;
又如何理解呢?
上面的方法中已经提到了,绝对定位相对于父元素 content 区域的原点定位,而相对定位则相对于父元素边框(border)最内侧定位,注意 ⚠️:不是相对于父元素的原点(左上角),而是边框内侧,这里差别很大,测试一下:
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
| <style> .outer { width: 500px; height: 500px; background-color: #000; position: relative; } .test { width: 100px; height: 100px; background-color: #00f; position: absolute; top: 50%; transform: translateY(-50%); float: left; }
.inner { width: 100px; height: 100px; background-color: #f00; position: absolute; top: 50%; transform: translateY(-50%); float: left; } </style>
<div class="outer"> <div class="test"></div> <div class="inner"></div> </div>
|
添加一个.test
元素,同时,让两个元素设置相同(除了背景色),可以看到元素重叠了,只能看到.inner
元素,说明它们定位的原点相同,所以才发生了重叠现象;
是不是float
属性影响了position
呢?将float
替换成display: inline-block;
后,结果一样;
接着测试将元素自身设置为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
| <style> .outer { width: 500px; height: 500px; background-color: #000; } .test { width: 100px; height: 100px; background-color: #00f; position: relative; top: 50%; transform: translateY(-50%); float: left; }
.inner { width: 100px; height: 100px; background-color: #f00; position: relative; top: 50%; transform: translateY(-50%); float: left; } </style>
<div class="outer"> <div class="test"></div> <div class="inner"></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
| <style> .outer { width: 500px; height: 500px; background-color: #000; }
.inner { width: 100px; height: 100px; background-color: #f00; position: relative; top: 50%; left: 50%; transform: translate(-50%, -50%); } </style>
<div class="outer"> <div class="inner"></div> </div>
|
方法五
还是常用方法之一,使用了 CSS3 新属性:父元素 display: flex; align-items: center;
;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <style> .outer { width: 500px; height: 500px; background-color: #000; display: flex; align-items: center; }
.inner { width: 100px; height: 100px; background-color: #f00; } </style>
<div class="outer"> <div class="inner"></div> </div>
|
没啥好说的,不熟悉 flex 属性的去 MDN 查看文档,align-items
属性描述了元素在交叉轴上的对齐方式;
至于绝对中,justify-content
则描述如何分配主轴元素之间及其周围的空间:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <style> .outer { width: 500px; height: 500px; background-color: #000; display: flex; align-items: center; justify-content: center; }
.inner { width: 100px; height: 100px; background-color: #f00; } </style>
<div class="outer"> <div class="inner"></div> </div>
|
方法六
由方法五演变而来,没怎么使用过:父元素 display: flex; 元素自身 align-self: center;
;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <style> .outer { width: 500px; height: 500px; background-color: #000; display: flex; }
.inner { width: 100px; height: 100px; background-color: #f00; align-self: center; } </style>
<div class="outer"> <div class="inner"></div> </div>
|
还是 CSS3 的新特性,align-self
会对齐 grid 或 flex 行中的元素,并覆盖已有的align-items
的值;
绝对居中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <style> .outer { width: 500px; height: 500px; background-color: #000; display: flex; justify-content: center; }
.inner { width: 100px; height: 100px; background-color: #f00; align-self: center; } </style>
<div class="outer"> <div class="inner"></div> </div>
|
方法七
CSS3 新特性,网格布局display: grid;
,示例就不写了, 把方法五和方法六中的display: flex;
换成display: grid;
就 OK 了;
方法八
终于要到display: table-cell;
了,一个古老的 CSS 特性;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <style> .outer { width: 500px; height: 500px; background-color: #000; display: table-cell; vertical-align: middle; }
.inner { width: 100px; height: 100px; background-color: #f00; } </style>
<div class="outer"> <div class="inner"></div> </div>
|
呃,不知道咋说,display: table-cell;
属性让元素以表格单元格的形式呈现,类似于 td 标签,而vertical-align
则用来指定行内元素(inline)或表格单元格(table-cell)元素的垂直对齐方式;
绝对居中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <style> .outer { width: 500px; height: 500px; background-color: #000; display: table-cell; vertical-align: middle; text-align: center; }
.inner { display: inline-block;
width: 100px; height: 100px; background-color: #f00; } </style>
<div class="outer"> <div class="inner"></div> </div>
|
是的,这里需要将元素转为行内(块)元素,因为text-align
属性只能定义行内内容(例如文字)如何相对它的块父元素对齐,却并不能控制块元素自己的对齐;
方法九
一种障眼法,基本没有使用场景,添加一个隐藏元素,将要显示的元素挤到中间位置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <style> .out { width: 500px; height: 500px; background-color: #000; } .hidden { height: 200px; } .in { width: 100px; height: 100px; background-color: #00f; } </style>
<div class="out"> <div class="hidden"></div> <div class="in"></div> </div>
|
这玩意儿就不必说绝对居中了吧?😂
结束
暂时就想到这么多,以后学到了新知识再做补充;
以上~