百度前端技术学院 第七天学习笔记(CSS 居中)

归纳了水平居中、垂直居中、水平+垂直居中的各种方式

水平居中

代码及效果可见codepen

补充:img是行内元素,为什么可以设置宽高?(面试题)

(题目来自魅族一面)
问题:既然img是行内元素,那为什么可以通过CSS设置宽高呢
答案:尽管img是行内元素,但同时它也是置换元素,置换元素一般内置框高属性,因此可以设置其宽高。
引申问题:那么什么又是“置换元素”呢?
答案:置换元素就是会根据标签属性来显示的元素。反之就是非置换元素了。比如img根据src属性来显示,input根据value属性来显示,因此可知道img和input是置换元素,当然同理select也是置换元素。


文本/内联/内联块元素(图片)的水平居中(text-align)

  • text-align属性定义行内内容(例如文字)相对它的块父元素的水平对齐方式。text-align 并不控制块元素自己的对齐,只控制它的行内内容的对齐。
  • 注意:text-align属性可用于 块级元素 来设置内部文本的水平对齐方式
  • 如果被设置元素为文本、图片等行内元素时,则需要**在父元素中设置text-align:center**实现行内元素水平居中(必要时可以将子元素的display设置为inline-block,使子元素变成行内元素的同时可设置样式)。
  • 补充:如果想水平居中一个块元素且不居中它的行内内容可将它的左、右margin设为auto, 例如:margin:auto;margin:0 auto;margin-left:auto; margin-right:auto;

代码及效果可见codepen

1
2
3
4
5
6
7
8
9
10
img {
width: auto;
height: auto;
/* 图片等比缩小 可借助max-width和max-height */
max-width: 200px;
max-height: 200px;
}
.txtCenter {
text-align: center;
}
1
2
3
4
5
6
7
8
9
10
11
12
<!-- 父元素设置text-align,图片水平居中 -->
<div class="txtCenter">
<img src="https://avatars.githubusercontent.com/u/46071177?v=4" />
</div>

<div class="txtCenter">
<span>父元素设置text-align,行内文本水平居中</span>
</div>

<p class="txtCenter">
块元素设置text-align,块内文本水平居中
</p>

效果图


实际常用:页签文本居中

  • 在实际工作中我们会遇到需要为“不定宽度的块级元素”设置居中,比如网页上的分页导航,因为分页的数量是不确定的,所以我们不能通过设置宽度来限制它的弹性
  • 可以通过给块元素/它的父元素设置text-align: center;实现块元素内文本的水平居中
  • 当不想不定宽块元素的宽度占一行时,可以设置display 为 inline 类型(行内元素 )或inline-block(行内块元素)【比如下面例子中的li元素】

代码及效果可见codepen

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.txtCenter {
text-align: center;
}
.container {
background: beige /* 米色 */
}
.container ul {
list-style: none;
margin: 0;
padding: 0;
}
.container li {
margin-right: 8px;
display: inline-block; /* li本来是块级元素,改下 */
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!--  
ul是块级元素,动态生成的页签数量,要实现li的文本居中显示
设置ul/父元素text-align: center;,则li继承居中的属性
-->
<div class="container txtCenter">
<ul>
<li><a href="#">1</a></li>
<li><a href="#">2</a></li>
<li><a href="#">3</a></li>
</ul>
</div>

<div class="container">
<ul class="txtCenter">
<li><a href="#">1</a></li>
<li><a href="#">2</a></li>
<li><a href="#">3</a></li>
</ul>
</div>

多个块级元素li的文本居中显示


(定宽)块级元素的水平居中(margin)

  • 当被设置元素为定宽块级元素时用 text-align:center 就不起作用了,可以通过设置“左右margin”值为“auto”来实现居中
  • 默认情况下,margin: auto;margin: 0 auto; 效果是一样的,都是水平居中,但纵向并没有任何变化。这是因为**margin-top: auto;margin-bottom: auto;,其计算值为0。而 水平方向的 auto,其计算值取决于可用空间(剩余空间)**
    • margin 是复合属性,也就是说 margin: auto; 相当于 margin: auto auto auto auto;margin: 0 auto;相当于 margin: 0 auto 0 auto;,四个值分别对应上右下左
    • 根据规范,在默认的书写模式 writing-mode: horizontal-tb; 和 文档流方向 direction: ltr; 的前提条件下,**margin-top: auto;margin-bottom: auto;,其计算值为0**。这也就解释了为什么默认条件下 margin: auto; 等同于 margin: 0 auto;

代码及效果可见codepen

1
2
3
4
5
6
7
8
9
.txtCenter {
text-align: center;
}
.w200 {
width: 200px;
}
.mgAuto {
margin: 0 auto;
}
1
2
3
4
5
6
7
8
9
10
<div class="txtCenter">
<!-- 放个居中的图片,更好感受文字是否居中 -->
<img src="https://avatars.githubusercontent.com/u/46071177?v=4" />
<div class="w200">
父元素设置text-align: center不能使块级子元素水平居中
</div>
<div class="w200 mgAuto">
定宽块级元素的水平居中(需要margin)
</div>
</div>

设置text-align的效果图

添加margin: 0 auto;后:
定宽块级元素水平居中


(不定宽)块元素内文本的水平居中(子绝父相/flex)

  • 为什么不定宽就不能通过 margin: auto 来水平居中?
    • 对于不定宽块级元素,margin: 0 auto; 不会使其水平居中,因为不定宽的块级元素会占据可用的水平空间,所以外边距没有多余的空间来进行自动分配
  • 重点补充:如果高度塌陷是因为absolute或fixed子元素脱离文档流,则给父元素设置BFC不管用,得设父元素高度

代码及效果可见codepen

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!-- 
position: absolute + left: 50% + transform: translateX(-50%)
display: flex + justify-content: center
-->
<!-- 绝对定位会脱离文档流,为了不影响其他元素设置BFC不能解决问题,必须设置父元素高度 -->
<div class="relative h40">
<!-- 不定宽块元素 -->
<div class="absolute-translate-center bgBeige">
position: translate + left + transform 子绝父相实现不定宽块元素水平居中
</div>
</div>

<div class="flex-jc-center">
<!-- 不定宽块元素 -->
<div class="bgBeige">
父元素设置 flex + justify-content 实现不定宽块元素水平居中
</div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
.absolute-translate-center {
position: absolute;
left: 50%;
transform: translateX(-50%);
}
/* 如果子元素脱离文档流是因为absolute或者fixed,则开启BFC不管用,得设父元素高度 */
.h40 {
height: 40px;
}
.relative {
position: relative;
}
.bgBeige {
background: beige; // 米色
}
.flex-jc-center {
display: flex;
justify-content: center;
}

垂直居中

代码及效果可见codepen
首先需要设定两个条件:父元素是盒子容器且高度已经设定

行内/块内 单行 文本垂直居中(line-height)

  • line-height 属性用于设置多行元素的空间量,如多行文本的间距。对于块级元素,它指定元素行盒(line boxes)的最小高度。对于非替代的 inline 元素,它用于计算行盒(line box)的高度。
  • 行内元素高度是由其内容撑开的这种情况下,需要给他一个固定高度的父元素盒子,通过设定父元素的line-height为行内元素设定高度,通过将父元素的line-height属性值设置与父容器高度相同即可使得子元素实现垂直居中。
  • 直接设置行内元素的line-height为想要的高度即可,文字将在内部居中

代码及效果可见codepen

1
2
3
4
5
6
7
8
.h200-box {
height: 200px;
border: 1px solid red;
}
span{
line-height: 200px;
background: gray;
}
1
2
3
<div class="h200-box">
<span>上校</span>
</div>

行内文本实现垂直居中

  • 或者子元素是没有给定高度的块级元素时也可以通过相同方法设置块级元素文字垂直居中下:
1
2
3
4
5
6
7
8
.h200-box {
height: 200px;
border: 1px solid red;
}
p{
line-height: 200px;
background: gray;
}
1
2
3
<div class="h200-box">
<p>上校</p>
</div>

块内单行文本实现垂直居中


内联块内多行文本/图片/不同类型 垂直居中(vertical-align)

  • vertical-align限制好多啊,避开它吧,能不用就不用
  • vertical-align 通常不会被继承,基本都在 元素自身上设置,但块元素居中是父元素设置vertical-align,图片居中是图自己设置vertical-align且不需要设置父元素单元格(但是父元素的高度要用行高代替,且字体大小设0),文本是父子都可,难搞
    • 特定情况下,父元素的 vertical-align 可能会对其子元素的垂直对齐产生一些影响(比如文本),但这通常适用于具有特殊要求的布局,并且可能会与其他 CSS 属性相互作用。一般来说,要实现准确的垂直对齐控制,你应该在需要垂直对齐的具体子元素上设置 vertical-align。
  • 通常用于行内元素(如文本、内联元素)中,以控制它们在同一行内的垂直对齐,特别适用于需要垂直居中不同类型内容的情况
  • 例子代码效果见codepen
  1. 行内元素的文本内容
  2. 内联块级元素中多行文本
  3. 行内元素或内联块级元素: 如图标、按钮、链接等,无论它们是包裹在行内元素还是内联块级元素中
  4. 图片: 父元素设置line-height: 高度px; font-size: 0; 图片设置img { vertical-align: middle; } (下面水平垂直居中里有例子)
  • 注意:图片居中时**父元素设置line-height: 高度px; font-size: 0;**图片设置img { vertical-align: middle; }原因可见张鑫旭大佬的博客
  • 需要img相对行内文字居中则设置img的vertical-align属性,单元格内文字的居中则设置单元格的vertical-align属性
  • 【问题】inline-block用vertical-align实现垂直怎么处理我还没搞出来
    • 【下面是机器人回答,有时间再倒回来看】对于 inline-block 元素,vertical-align 也可以生效,但需要注意以下几点:
      • vertical-align 对于 inline-block 元素控制的是元素相对于其父元素的垂直对齐。它通常用于控制 inline-block 元素相对于父元素中的其他内容(例如文本)的垂直位置。
      • 通常需要配合父元素适当的 line-height 和 height 设置来实现。例如,你可以设置父元素的 line-height 与父元素的高度相等,然后将 vertical-align 设置为 middle,以实现垂直居中。

补充:vertical-align 属性

  • vertical-align 和 line-height 关系匪浅,可拜读张鑫旭大佬的博客
  • vertical-align 属性指定行内元素(inline)或表格单元格(table-cell)元素 相对父元素垂直对齐方式
    • baseline:使元素的基线父元素的基线对齐。
    • middle:使元素的中部与父元素的基线加上父元素x-height(x高度)的一半对齐。
    • 更多属性可参考这里
  • 作用于:display属性值为inline、inline-block、inline-table另加一个table-cell的元素。(可参考这篇文章
  • 注意:不能用它垂直对齐块级元素。
  • 关于基线的位置(不是固定的):
    • 文本之类内联元素中,基线是字符x的下边缘位置
    • 在像img元素中基线就是下边缘
    • inline-block元素中,也分两种情况:
      • 如果该元素中有内联元素,基线就是最后一行内联元素的基线
        • 如果该元素内没有内联元素或者overflow不是visible,其基线就是margin的地边缘
  • 注意:vertical-align不作用于span元素,原因如下:
    • 实际上,一个Box中由很多行很多元素组成,vertical-align只作用于在同一行内的元素,它的垂直并不是相对于整个Box而言的。是相对同一行
      • 一个 span定义了一个60px的高度,但是这个span的Box中存在很多行,那段文本并不能对齐到span的中央。因此希望那段文本对齐span的中行需要给它定义一个line-height的属性,让line-height为60px,作用于一行的vertical-align就按你的想法工作了。
      • table的单元格,因为是一行内的元素,因此vertical-align按照我们的想法来工作,但是在span中并不是这样的。
  • 说到这感觉line-height可以替代vertical-align,但实际不是的。vertical-align使用场景:当一个文本后面跟着个inline-block的元素时,后者是对齐文本的基线的,这就导致文本看上去被挤下来了一样,使用vertical-align: top/text-top就可以解决这个问题,这是line-height解决不了的。(还有这个常见的图片问题

补充:display:table-cell;表格单元格

  • 设置display:table-cell;会使此元素会作为一个表格单元格显示(类似 <td> <th>)。
  • 可以通过在.table-cell中添加vertical-align:middle使表格内部文字垂直居中
    表格布局对比

(不定高)块级元素垂直居中

  • 代码及效果可见codepen
  • 子元素是块级元素但是子元素高度没有设定,在这种情况下实际上是不知道子元素的高度的,无法通过计算得到padding或margin来调整,但是还是存在一些解法。

方法1(单元格vertical-align)

  • 能避则避vertical-align!!
  • 通过**给父元素设定display: table-cell; vertical-align: middle;**来实现没有定高的块级子元素文本垂直居中
    • vertical-align 通常不会被继承,全部都在 元素自身上设置,除了文本居中可以在父元素设置(但还是建议在元素自身上设置)
  • 代码及效果可见codepen
1
2
3
4
5
6
7
8
9
10
.dad {
height: 200px;
display: table-cell;
vertical-align: middle;
border: 1px solid red;
}
p {
background: gray;
margin: 0;
}
1
2
3
<div class="dad">
<p>上校</p>
</div>

没有定高的块级元素垂直居中

方法2(line-height+inline-block)

给块级元素设置display:inline-block,然后使用行内元素的line-height属性实现垂直居中。
代码及效果可见codepen

补充:绝对定位/固定定位/浮动 都会使元素变为inline-block元素

方法3(flex + align-items)

给父元素使用display: flex;将其设置为弹性盒子父容器,然后设置align-items: center;定义子项在交叉轴上的对齐方式:
代码及效果可见codepen

1
2
3
4
5
6
7
8
9
10
.dad {
height: 200px;
border: 1px solid red;
display: flex;
align-items: center;
}
p {
background: gray;
margin: 0;
}
1
2
3
<div class="dad">
<p>上校</p>
</div>

使用弹性盒子实现垂直居中

方法4(子绝父相 + top + transform)

position:absolute + top:50% + transform: translateY(-50%)
代码及效果可见codepen

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.relative {
position: relative;
}
.h200-box {
width: 600px;
height: 200px;
border: 1px solid red;
margin-bottom: 10px;
p {
margin: 0; /* p有自己的margin,处理下*/
}
}
.absolute-translate-center {
position: absolute;
top: 50%;
transform: translateY(-50%);
}
1
2
3
4
5
6
<div class="relative h200-box">
<p class="absolute-translate-center">
position:absolute + top:50% + transform: translateY(-50%)实现(不定高)块元素垂直居中
注意相对定位的元素要给高度,BFC解决不了绝对定位的高度塌陷问题
</p>
</div>

(定高)块级元素垂直居中

方法1(直接算margin)

此时可以计算子元素的margin-top或margin-bottom,将其设置为**(父元素高度-子元素高度)/2**

1
2
3
4
5
6
7
8
9
10
.dad {
height: 200px;
border: 1px solid red;
}
p {
background: gray;
margin: 0;
height: 40px;
margin-top: 80px;
}
1
2
3
<div class="dad">
<p>上校</p>
</div>

定高的块级元素实现垂直居中

方法2(flex+margin设auto)

父元素display:flex,子元素margin:auto 0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
.flex {
display: flex;
}
.h200-box {
width: 600px;
height: 200px;
border: 1px solid red;
margin-bottom: 10px;
}
.mg-auto-0 {
margin: auto 0;
}
.h40 {
height: 40px;
}
.bgBeige {
background: beige; /* 米色 */
}
1
2
3
4
5
<div class="flex h200-box">
<div class="mg-auto-0 bgBeige h40">
父元素`display:flex`,子元素`margin:auto 0`实现定高块元素垂直居中!!!
</div>
</div>

方法3(子绝父相 + top、bottom、left、right设0 + margin设auto)

效果见codepen

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
.relative {
position: relative;
}
.absolute {
position: absolute;
}
.h200-box {
width: 600px;
height: 200px;
border: 1px solid red;
margin-bottom: 10px;
}
.mg-auto-0 {
margin: auto 0;
}
.h40 {
height: 40px;
}
.bgBeige {
background: beige; /* 米色 */
}
1
2
3
4
5
<div class="relative h200-box">
<div class="absolute all0 mg-auto-0 bgBeige h40">
position: translate + top、bottom、left、right设为0 + margin: auto 0 子绝父相实现定高块元素垂直居中
</div>
</div>

水平+垂直居中

效果见codepen

text-align + line-height块/行内元素单行文本双向居中

text-align + line-height实现块内单行文本水平垂直居中:

1
2
3
4
5
6
div {
text-align: center;
line-height: 100px;
background: gray;
width: 200px;
}
1
<div>上校,喵</div>

居中

注意:行内元素要实现居中就要去给他的父元素设置,垂直居中就通过父元素line-height给子元素一个高度,再通过父元素设置text-align:center实现行内元素水平居中:

1
2
3
4
5
6
7
8
9
span {
background: gray;
width: 200px;
}
.dad {
text-align: center;
line-height: 100px;
border: 1px solid red;
}
1
2
3
<div class="dad">
<span>上校,喵</span>
</div>

行内元素双向居中


text-align + vertical-align实现文本/内联/内联块元素(图片)双向垂直

  • 放过vertical-align吧,复杂到问了一圈同事没人在用
  • 上面有说到vertical-align是只作用于在同一行内的元素,它的垂直并不是相对于整个Box而言的。而table的单元格是一行内的元素,因此vertical-align生效。

注意:子元素需要设置为inline-block,父元素需要设置高度。

1
2
3
4
5
6
7
8
9
10
11
12
span {
background: gray;
width: 200px;
display: inline-block;
}
.dad {
display: table-cell;
text-align: center;/* 行内元素给父元素设置text-align可水平居中 */
height: 200px;
vertical-align: middle;
border: 1px solid red;
}
1
2
3
<div class="dad">
<span>上校,喵</span>
</div>

效果图

子元素是图像,可不使用table-cell,而是其父元素用行高替代高度,且字体大小设为0。子元素本身设置vertical-align:middle

1
2
3
4
5
6
7
8
9
10
11
12
13
.dad {
text-align: center;/* 行内元素给父元素设置text-align可水平居中 */
line-height: 200px;
font-size: 0;
border: 1px solid red;
}
img {
vertical-align: middle;
width: auto;
height: auto;
max-width: 200px;
max-height: 200px;;
}
1
2
3
<div class="dad">
<img src="https://avatars.githubusercontent.com/u/46071177?v=4">
</div>

效果图


相对+绝对定位

行内元素进行绝对定位/固定定位后会变成inline-block元素

使用absolute,利用绝对定位元素的盒模型特性,在偏移属性为确定值的基础上,设置margin:auto

注意: 子元素需要定高定宽!!
代码和效果可见codepen

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
span {
background: gray;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
height: 100px;
width: 100px;
margin: auto;
}
.dad {
position: relative;
border: 1px solid red;
width: 200px;
height: 200px;
}
1
2
3
<div class="dad">
<span>上校,喵</span>
</div>

绝对定位子元素居中

,