归纳了水平居中、垂直居中、水平+垂直居中的各种方式
水平居中
代码及效果可见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: 200px; max-height: 200px; } .txtCenter { text-align: center; }
|
1 2 3 4 5 6 7 8 9 10 11 12
| <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; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
<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>
|
(定宽)块级元素的水平居中(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>
|
添加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
|
<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%); }
.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
- 行内元素的文本内容
- 内联块级元素中多行文本
- 行内元素或内联块级元素: 如图标、按钮、链接等,无论它们是包裹在行内元素还是内联块级元素中
- 图片: 父元素设置
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>
|
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; } } .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; }
|
注意:行内元素要实现居中就要去给他的父元素设置,垂直居中就通过父元素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; 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; 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>
|