总结CSS水平垂直居中的各种骚操作

总结CSS水平垂直居中的各种骚操作

CSS 是世界上最难的语言! #(手动滑稽)
​ ———— 啊哈呵嗨

水平居中

NameTag
margin:0 auto;基础, 常用
利用 inline-block基础, 常用
width:fit-content;CSS3
width:fill-available;CSS3

垂直居中

NameTag
padding上下相等基础, 常用
line-height基础, 常用
CSS 表(table)布局 👍常用
“精灵元素”,利用伪类实现 👍奇技淫巧

水平垂直居中

NameTag
“完全居中法” 👍基础, 常用
margin 负值法基础, 常用
translate 负值50%变换CSS3, 常用
CSS3 flex(弹性)布局 👍CSS3, 常用
vw vh和translate 👍CSS3
通过JavaScript代码实现居中JavaScript
通过隐藏节点+float
利用CSS3 grid(网格)布局CSS3
object-fit和object-postion居中奇技淫巧

水平居中

margin:0 auto

可以说是极为常用了

通过把 固定宽度块级元素margin-leftmargin-right 设成 auto,就可以使块级元素水平居中。

1
2
3
4
5
6
7
8
9
10
11
12
.box {
width: 300px;
height: 300px;
border: 3px solid red;
/*text-align: center;*/
}
img {
display: block;
width: 100px;
height: 100px;
margin: 0 auto; //关键的一句话
}
1
2
3
<div class="box">
<img src="img1.jpg" alt="这是一张图片" />
div>

⚠️ 注意事项

前提是不受 float 影响

利用 inline-block

利用 text-align: center 可以实现在块级元素内部的内联元素水平居中。
此方法对 内联元素(inline), 内联块(inline-block), 内联表(inline-table), inline-flex 元素 水平居中都有效。

如果一行中有两个或两个以上的块级元素,可将元素的 display 属性设置为 inline-block,并把父元素的 text-align 属性设置为 center:

1
2
3
.parent {
text-align: center;
}
1
2
3
4
5
6
7
/*多个子元素时*/
.container {
text-align: center;
}
.inline-block {
display: inline-block;
}

width:fit-content

width:fit-content 也是应该比较好理解的,“shrink-to-fit”表现,换句话说,和 CSS2.1 中的 float, absolute, inline-block 的尺寸收缩表现是一样的
OK,然后,有小伙伴会疑问,既然跟很多 CSS 声明有一样的表现,那为什么还要再弄个新东西呢?
就拿水平居中效果举例,首先浮动肯定不行,因为只有左浮动和右浮动;绝对定位压根不占据空间,普通流中根本无法应用,而 inline-block 需要父级使用 text-align:center,而本身可能还需要 text-align:left 略烦。
而 width:fit-content 可以没有这些烦恼,因为,width:fit-content 可以实现元素收缩效果的同时,保持原本的元素 block 水平状态,于是,就可以直接使用 margin:auto 实现元素向内自适应同时的居中效果了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
.box {
background-color: #f0f3f9;
padding: 10px;
/* 这里左右方向是auto */
margin: 10px auto 20px;
overflow: hidden;
}

.inline-block {
display: inline-block;
}
.fit-content {
width: -webkit-fit-content;
width: -moz-fit-content;
width: fit-content;
}
1
2
3
4
5
6
7
8
9
10
11
<strong>display:inline-block;strong>
<div class="box inline-block">
<img src="mm1.jpg" />
<p>display:inline-block居中要靠父元素,而width:fit-content直接margin:auto.p>
div>

<strong>width: fit-content;strong>
<div class="box fit-content">
<img src="mm1.jpg" />
<p>display:inline-block居中要靠父元素,而width:fit-content直接margin:auto.p>
div>

解释

“fit-content”是 CSS3 中给“width”属性新加的一个属性值,它配合 margin 可以很轻松实现水平居中的效果

width:fill-available

width:fill-available 比较好理解,比方说,我们在页面中扔一个没有其他样式的

元素,则,此时,该
元素的 width 表现就是 fill-available,自动填满剩余的空间。也就是我们平常所说的盒模型的 margin,border,padding 的尺寸填充。
出现 fill-available 关键字值的价值在于,我们可以让元素的 100%自动填充特性不仅仅在 block 水平元素上,其他元素,例如,我们一直认为的包裹收缩的 inline-block 元素上:

1
2
3
4
div {
display: inline-block;
width: fill-available;
}

此时,元素兼具了块状元素的自动填充特性以及内联元素的定位对齐等特性(vertical-align/height/line-height)。于是,(例如)我们就可以直接使用 line-height 让一个块状表现的元素垂直居中


垂直居中

padding 上下相等

最基础的方法,只需添加等值的 padding-toppadding-bottom 就可以实现垂直居中(margin也行)

1
2
3
4
.ct {
padding: 40px 0;
/*text-align: center;*/
}
1
2
3
4
<div class="ct">
<p>这里是文字p>
<img src="img1.jpg" alt="这里是图片" />
div>

line-height

最简单的一种使 单行内联(inline-)元素(单行文字) 垂直居中的方法

如果因为某些原因我们不能使用 padding 属性来实现垂直居中,而且已知文本不会换行,

那么就可以让 line-height(行高)height(高度) 相等,从而实现垂直居中:

1
2
3
4
#v-box {
height: 120px;
line-height: 120px;
}

CSS 表(table)布局 👍

总的说来这可能是最好的居中实现方法,因为内容块高度会随着实际内容的高度变化,浏览器对此的兼容性也好。

最大的缺点是需要大量额外的 html 标签,需要 2~3 层元素让最内层的元素居中。

利用表布局的 vertical-align: middle 可以轻松实现子元素的垂直居中

1
2
3
4
5
6
7
8
9
10
11
.center-table {
display: table;
}
.v-cell {
/*让元素渲染为表格单元格*/
display: table-cell;
/*设置文本水平居中*/
text-align: center;
/*设置文本垂直居中*/
vertical-align: middle;
}

解释

CSS 中的确是有 vertical-align 属性,但是它只对(X)HTML 元素中拥有 valign 特性的元素才生效,例如表格元素中 的等,而像

这样的元素是 没有 valign 特性的,因此使用 vertical-align 对它们不起作用

但是在 CSS 中还有一个 display 属性能够模拟

,所以我们可以使用这个属性来让
模拟
就可以使用 vertical-align 了。注意,display:table 和 display:table-cell 的使用方法,前者必须设置在父元素 上,后者必须设置在子元素上,因此我们要为需要定位的文本再增加一个
元素

“精灵元素”,:before 和 display:inline-block 👍

利用 “精灵元素”(ghost element) 实现垂直居中,即 通过伪类:before 在父容器内增加新元素后在用 display:inline-block,通过 100%高度的处理让文本和伪元素垂直对齐,从而得到想要的效果。

有点 CSS Hack 的骚味

1
2
3
4
5
6
7
8
9
10
11
12
.container {
  text-align: center;
}
.container:before {
  content: "";
  display: inline-block;
  height: 100%;
  vertical-align: middle;
}
.inner {
  display: inline-block;
}
1
2
3
<div class="container">
<div class="inner">this is a box fixed in center of screen<br />The second linediv>
div>
  • 解释

这个方案是比较特别一些,不是很好理解。

首先,.container 水平居中没问题。

接着,给.container 伪类:before 设定为 height:100%,这样可以用一个伪元素在.container 获得与父元素等高的空间。

然后用 inline-block 和 vertical-align: middle 改变对齐的基线。

通过:before 之后,.container 内的行级元素的对齐基线就跑到居中的位置,也就实现了垂直居中对齐。

这个时候,如果里面仅一排文字,其实可以不用.inner,但是上面的例子里面有一个
,这就不一样了。
如果直接把文字放在.container 里面,
之前的文字会基于:before 基线,会保持垂直对齐的状态。
但是
之后的文字会另起一行,这一行将起始于:before 的下一行,所以会在:before 的 100%高度下面,导致被顶出.container。
但是如果把文字放在.inner 里面,再让.inner 为 inline-block,就可以使.inner 和:before 处于同一基线,这样就让整个.inner 处于垂直中的状态。

强大的 writing-mode

我们应该都是这样的的,传统的 web 流中,margin 设置 auto 值的时候,只有水平方向才会居中,因为默认 width 是 100%自适应的,auto 才有计算值可依,而垂直方向,height 没有任何设置的时候高度绝不会自动和父级高度一致,因此,auto 没有计算空间,于是无法实现垂直居中。但是,在 writing-mode 的世界里,纵横规则已经改变,元素的行为表现发生了翻天覆地的变化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.box {
width: 400px;
height: 300px;
background-color: #f0f3f9;
overflow: hidden;
}
.auto {
display: block;
margin-top: auto;
margin-bottom: auto;
}

.verticle-mode {
writing-mode: tb-rl;
-webkit-writing-mode: vertical-rl;
writing-mode: vertical-rl;
}
1
2
3
4
5
6
7
8
9
<p><strong>默认流-margin-top:auto;margin-bottom:auto不居中strong>p>
<div class="box">
<div class="auto">div块状元素div>
div>

<p><strong>垂直流-margin-top:auto;margin-bottom:auto垂直居中strong>p>
<div class="box verticle-mode">
<div class="auto">div块状元素div>
div>

具有如下优点的水平垂直居中效果:

  • 上下左右居中
  • 纯 css 实现
  • 无定位
  • 居中元素不需要设置宽高
  • 适应性超强
  • 兼容 ie8

demo 地址为:https://liyongleihf2006.github.io/center-box/


水平垂直居中

“完全居中法” 👍

绝对定位 + 0 + margin:auto 组合使用,简单粗暴

当我们要制作一个 modal dialog 弹出框时,比如弹出居中于屏幕的广告或登录框。这个时候可以考虑一些相对于窗口或网页居中的方案。

1
2
3
4
5
6
7
8
9
10
11
/*.center-container {
position: relative;
}*/
.absolute-center {
position: absolute; /*或者fixed,记得要设置z-index*/
top: 0;
right: 0;
bottom: 0;
left: 0;
margin: auto;
}

margin 负值法

适用于 固定宽高的块级元素

这或许是当前最流行的使用方法。如果块元素尺寸已知,可以通过以下方式让内容块居中于容器显示:

外边距 margin 取负数,大小为 width/height(不使用 box-sizing: border-box 时还包括 padding)的一半,再加上 top: 50%; left: 50%;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/*.parent {
position: relative;
}*/

.child {
top: 50%;
width: 100px;
height: 100px;
margin-top: -50px;
/* margin-top值为自身高度的一半 */
margin-left: -50px;
position: absolute;
padding: 0;
}

position:absolute、50%和 translate 👍

利用 CSS3 translate 的 2D 变换,在水平和垂直两个方向都向反向平移宽高的一半,从而使元素 水平垂直居中。

若只是水平居中,请使用 translateX(-50%)

若只是垂直居中,请使用 translateY(-50%)

1
2
3
4
5
6
7
8
9
10
.ele {
/*设置元素绝对定位*/
position: absolute;
/*top 50%*/
top: 50%;
/*left 50%*/
left: 50%;
/*css3 transform 实现*/
transform: translate(-50%, -50%);
}

CSS3 flex(弹性)布局 👍

多个块状元素解决方案,简单粗暴

只需把待处理的块状元素的父元素添加属性 display:flex 及 justify-content:center 即可:

1
2
3
4
5
6
7
8
9
10
.flex-center {
/*弹性盒模型*/
display: flex;
/*垂直方向排布*/
/*flex-direction: column;*/
/*主轴居中对齐*/
justify-content: center;
/*侧轴居中对齐*/
align-items: center;
}

解释

简单解释一下,当 display:flex 时,表示该容器内部的元素将按照 flex 进行布局。

其中 justify-content 用于设置或检索弹性盒子元素在主轴(横轴)方向上的对齐方式;
而 align-items 属性定义 flex 子项在 flex 容器的当前行的侧轴(纵轴)方向上的对齐方式。

对.container 赋予了这些样式之后,作为它的内部元素.inner 自己自觉的居中了。
而且这里你会发现,由于没有使用 text-align:center,.inner 里面的文字是不会居中的,也就是说仅仅.inner 这个容器居中而已。

⚠️ 注意事项

Flexbox 是 CSS3 新增属性,设计初衷是为了解决像垂直居中这样的常见布局问题。

记住 Flexbox 不只是用于居中,也可以分栏或者解决一些令人抓狂的布局问题。

但是会存在浏览器的兼容问题。

vw vh 和 translate 👍

vh 和 vw 是 CSS3 新增的单位,是指“viewport 的 height 和 width 的 1%”

比如说 50vh 就是当前视口(窗口的高度,实验中包含了滚动条)高度的 50%。也就是说 vw 将获得和 1%差不多的 window 宽度。因此用在 fixed 的时候更加适合。

1
2
3
4
5
6
.inner {
position: fixed;
top: 50vh;
left: 50vw;
transform: translate(-50%, -50%);
}
1
2
3
<div class="inner">
this is a box fixed in center of screen
div>

其实和使用 50%没有太大的差别,因为这时 top、left 取的 50%是相对于父元素的,和 margin、padding 不一样。如果非得要 margin 的话,就可以从这里衍生出变体:

1
2
3
4
5
6
7
.inner2 {
position: fixed;
top: 0;
left: 0;
margin: 50vh 0 0 50vw;
transform: translate(-50%, -50%);
}

vh vw 只能从窗口的大小去考虑,不适合正常的文本流。不过有的时候可以非常有用,特别是在做全屏应用的时候,比如 full page。

通过 JavaScript 代码实现居中

原生 js 实现

1
2
3
4
5
6
div {
padding: 50px;
display: inline-block;
background-color: pink;
position: absolute;
}
1
2
3
4
5
window.onload = function() {
var div = document.querySelector("div"); // 获取元素
div.style.left = (window.innerWidth - div.offsetWidth) / 2 + "px"; // 设置left
div.style.top = (window.innerHeight - div.offsetHeight) / 2 + "px"; // 设置top
};

jQuery 实现水平和垂直居中

jQuery 实现水平和垂直居中的原理就是通过 jQuery 设置 DIV 的 CSS,获取 DIV 的左、上的边距偏移量,边距偏移量的算法就是用页面窗口的宽度减去该 DIV 得宽度,得到的值再除以 2 即左偏移量,右偏移量算法相同。注意 DIV 的 CSS 设置要在 resize() 方法中完成,就是每次改变窗口大小时,都要执行设置 DIV 的 CSS,代码如下:

1
2
3
4
5
6
7
$(window).resize(function() {
$(".mydiv").css({
position: "absolute",
left: ($(window).width() - $(".mydiv").outerWidth()) / 2,
top: ($(window).height() - $(".mydiv").outerHeight()) / 2
});
});

此外在页面载入时,就需要调用 resize()。

1
2
3
$(function() {
$(window).resize();
});

此方法的好处就是不需要知道 DIV 的具体宽度和高度大小,直接用 jQuery 就可以实现水平和垂直居中,而且兼容各浏览器,这个方法在很多的弹出层效果中应用。

通过隐藏节点+float

我们可以通过增加一个隐藏节点,然后使其float:left,这样子元素就会被隐藏节点推着水平居中。

这种增加隐藏节点方法也适用于 CSS 垂直居中,原理一样,但是不用 float。

利用 CSS3 grid(网格)布局

利用 grid 实现水平垂直居中,CSS3 的最新技术,但兼容性较差,生产环境中不推荐。

1
2
3
4
5
6
7
8
.parent {
height: 140px;
display: grid;
}

.child {
margin: auto;
}

object-fit 和 object-postion 居中

object-fit 只能用于可替换元素(replaced element) ,用以

指定替换元素的内容应该如何适应到其使用的高度和宽度确定的框。

一般用做图片的样式。它有着类似 background-image 的用法:

1
2
3
4
.center {
object-fit: fill|cover|contain|none|scale-down;
/*其属性值,分别是填充(默认)、包含、覆盖(可能被裁剪)、无变化(保持原状)和等比例缩放*/
}

而 object-positon 属性默认值是50% 50%,也就是居中(也就是要求居中的情况不用写这个属性了……),对元素定位控制,类似 background-postion。

空标签

无形中添加了空标签,所以不建议使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
.wrap {
width: 400px;
height: 400px;
background: #fcf;
/*行高等于高度,垂直居中*/
line-height: 400px;
/*水平居中*/
text-align: center;
}
.wrap img {
/* 图片按道理需要设置display:block,在这边条件的限制,所以我们没有设置了 */
/* display: block; */
width: 200px;
height: 200px;
/*垂直居中*/
vertical-align: middle;
}
.wrap span {
display: inline-block;
}
1
2
3
4
<div class="wrap">
<img src="Koala.jpg" alt="" title="" />
<span>span>
div>

注意:添加了 span 标签,并且设置 display 属性设置为 inline-block 来使我们 span 标签拥有”layout”,这样就解决了在 IE6 不能兼容的问题.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
html,
body {
height: 100%;
}
.box {
position: relative;
/*清除浮动*/
clear: both;
height: 300px;
width: 300px;
margin: 0 auto;
background: #999;
}
.floater {
float: left;
/*相对于父元素高度的50%*/
height: 50%;
/*居中元素高度的一半*/
margin-bottom: -150px;
background: #fcf;
}

网易 NEC 方法

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
<div class="floater">div>
<div class="box">
独行冰海、梦幻雪冰
div>


<html>
<head>
<meta charset="UTF-8" />
<title>HTML5Course - HTML5学堂title>
<link rel="stylesheet" href="reset.css" />
<script type="text/javascript" src="jquery-1.8.3.min.js">script>
<style>
html,
body {
width: 100%;
height: 100%;
}
.wrap {
position: relative;
width: 100%;
height: 100%;
}
.wrap > div {
/*父级设置定位*/
position: absolute;
left: 50%;
top: 50%;
}
.wrap img {
/*设置图片大小*/
display: block;
width: 200px;
height: 200px;
}
.wrap img:nth-child(1) {
/*第一张图片隐藏*/
visibility: hidden;
}
.wrap img:nth-child(2) {
/*第二张图片定位*/
position: absolute;
left: -50%;
top: -50%;
}
style>
head>
<body>
<div class="wrap">
<div>
<img
src="https://mmbiz.qlogo.cn/mmbiz/p6DwiaCENIB6pR8GhsfVeo7382t1SicdA8iahVpBPSRMaFPaHHLXuyXvkryL43R4GuLMOrhVvDFwwfprmH9f9EgVg/0?wx_fmt=jpeg"
alt="HTML5学堂"
/>
<img
src="https://mmbiz.qlogo.cn/mmbiz/p6DwiaCENIB6pR8GhsfVeo7382t1SicdA8iahVpBPSRMaFPaHHLXuyXvkryL43R4GuLMOrhVvDFwwfprmH9f9EgVg/0?wx_fmt=jpeg"
alt="HTML5学堂"
/>
div>
div>
body>
html>

效果分析

它的父级 div 设置 left、top 各自为 50%,这一步相信大家还是可以理解,就不详细做介绍了。

那么为什么要用两张图片?

大家仔细看看,该方法是没有给父级设置宽高,是靠图片来撑开,所以有一张图片是撑开父级的宽高。

另外一张图片设置 left、top 为 50%,意思就是相对它的父级定位,left、top 都是父级宽高的一半(父级的宽高等于图片的宽高)

效果原理分析

这种方法的优势

优点是可以不知道图片的大小,随便放张尺寸上去都能做到居中。另外,兼容性好,如果是不使用 nth-child 选择器的话,IE6 都能兼容的

calc()居中

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

<html>
<head>
<meta charset="UTF-8" />
<title>HTML5Course - HTML5学堂 - 利用CSS3的calc( )实现水平垂直居中title>
<link rel="stylesheet" href="reset.css" />
<style>
.wrap {
width: 400px;
height: 400px;
background-color: #ccc;
}
.wrap .con {
/*利用CSS3的calc() ,它的用法类似于函数,能够给元素设置动态的值:*/
/*(父级的宽度 - 自身的宽度)的一半当做padding的值*/
padding: -webkit-calc((100% - 100px) / 2);
padding: -moz-calc((100% - 100px) / 2);
padding: -ms-calc((100% - 100px) / 2);
padding: calc((100% - 100px) / 2);
width: 100px;
height: 100px;
background-color: pink;
color: #fff;
/*背景只显示内容区域*/
background-clip: content-box;
}
style>
head>
<body>
<div class="wrap">
<div class="con">HTML5学堂 - 刘国利、陈能堡div>
div>
body>
html>

calc()属于 CSS3,用于动态计算长度值,可以用在任何一个需要的地方。有了 calc(),你可以通过计算来决定一个对象的大小和形状。还可以在一个 calc()内部嵌套另一个 calc()。妈妈再也不担心我水平垂直居中不了了。

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×