简单易懂的CSS实现水平居中和垂直居中

  最早开始学习 HTML 的时候,就看了居中应该怎么居中,实际做东西的时候遇到还是会去翻翻笔记,或者几种方法挨个试效果,撞到哪个对了就对了。还是想把这个梳理一下,希望以后在遇到居中需和不居中问题的时候可以快速清晰地定位。


  先回忆一下行内元素和块状元素。
  行内元素(又称内联元素),相邻的行内元素会排列在同一行里,如果一行排不下,才会换行,比如 <a> <img>,其宽高都由元素自身内容决定,对于行内元素来讲,设置 widthheight 就没啥用了。
  块级元素,自己独占一行,比如 <div>,宽度占满其父元素宽度,相邻的块级元素自上而下垂直排列,不会显示在一行。
  块级元素可以设置 widthheight,不过即使设置了宽,块级元素仍旧会占一整行,相邻的元素还是会换行显示。因为我们所定义的 width 仅仅是图中蓝色区域 content 的宽:
  盒子模型
  上图中的 marginpadding 属性,块级元素可以设置 margin 和 padding 四个方向的属性,而行内元素只有水平方向(left\right)的 padding 和 margin 会产生效果,垂直方向无效。
  块级元素列表
  行内元素列表
  可变元素

水平居中

  水平居中网上也有很多总结,一般分为行内元素和块级元素再根据不同情况来区分使用,这里写一下自己的理解。最基础的无非就是 margin:autotext-align:center,前者是自己想要居中于父模块,后者是内容想要居中于自己。

举一个例子

1
2
3
4
5
6
<!--001-->
<div style="width:200px; margin:auto">
<h3>文字</h3> <!--文本信息-->
<img src="logo.svg" width="100px;" /> <!--图片,行内元素-->
<div style="width:20px;height:20px;background-color:yellow;"></div> <!--块级元素-->
</div>

001
  如上图,蓝色区域即 div 居中在 body,div 包含的内容并不居中。下面我们把 margin:auto 改成 text-align:center

1
2
3
4
5
6
<!--002-->
<div style="width:200px; text-align:center">
<h3>文字</h3> <!--文本信息-->
<img src="logo.svg" width="100px;" /> <!--图片,行内元素-->
<div style="width:20px;height:20px;background-color:yellow;"></div> <!--块级元素-->
</div>

002
  图中 div 本身相对 body 来讲并不居中,而是 div 里面的内容相对于 div 居中了(暂且忽略小黄块)。我们可以改变一下 div 的 width ,多次验证一下。下面我们把父容器的宽度去掉试试:

1
2
3
4
5
6
<!--003-->
<div style="text-align:center">
<h3>文字</h3> <!--文本信息-->
<img src="logo.svg" width="100px;" /> <!--图片,行内元素-->
<div style="width:20px;height:20px;background-color:yellow;"></div> <!--块级元素-->
</div>

003
  我们看到 div 继承了父容器 body 的宽度,如前文所说的块级元素的特征体现。
下一步思考
  我们通过上面的例子知道了 margin:autotext-align:center 的基本用法,但是也发现似乎不能一概而论,比如前面那个没有被居中的小黄块。因为它们在使用的时候也是有条件的。

margin:auto 使自己相对于父元素居中,只有在自身 width 声明的情况下才生效。
text-align:center 使子元素相对于自己居中,只对内容中的文本信息、行内元素有效。

  想想怎么把上面那个小黄块再居中就很简单了,因为它是有 width 的,只需要添加一个 margin:auto 属性就可以了。那如果这个小黄块的 width 是不一定的呢。
  假如预期是给这个 div 一点内容,内容多宽背景色就多宽:

1
2
3
4
5
6
7
8
<!--004-->
<div style="text-align:center">
<h3>文字</h3> <!--文本信息-->
<img src="logo.svg" width="100px;" /> <!--图片,行内元素-->
<!--块级元素-->
<div style="width:20px;height:20px;background-color:yellow;margin:auto"></div>
<div style="background-color:green;">宽度不定的块级元素</div>
</div>

004
  我们发现图中的绿色 div 并不符合我们的预期,背景色超出了本身的内容,话说里面的文字为什么居中呢,是因为父元素 div 的 text-align:center 使得文本内容居中。

下面来看看怎么解决不定宽度块级元素的居中问题吧:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!--005-->
<!--初始状态-->
<div style="background-color:green;">宽度不定的块级元素</div>
<!--table方法-->
<table align="center">
<tr>
<td>
<div style="background-color:green;">宽度不定的块级元素,方法1</div>
</td>
</tr>
</table>
<!--将div的块级属性使用display改变为内联属性-->
<div style="text-align:center;">
<div style="display:inline; background-color:green;">宽度不定的块级元素,方法2</div>
</div>
<!--使用相对定位-->
<div style="float:left; position:relative; left:50%;">
<div style="position:relative; left:-50%; background-color:green;">宽度不定的块级元素,方法3</div>
</div>



  • 用 table 包围后,使用 table 的特性使其居中
  • display 改变了 div 本身块级元素的性质,使用时需要注意连带影响

垂直居中

  • 垂直居中最简单的一种情况,单行文本,设置 line-height 的值等于 height,这个方法仅限于单行文本,如果换行的话布局会乱掉,使用的时候最好添加一条属性 overflow:hidden
  • vertical-align:middle也是常常会看到的一个用户垂直居中的设置,使用这个属性的时候可以将对象用 table 包裹,设置 table 的 style 属性(类似水平居中的 table 方法),或者直接将其设置 display:table-cell,再添加这个属性,不过 display 操作改变了元素本身的性质,使用时要注意连带影响。

    vertical-align 是定义行内元素的基线相对于该元素所在行的基线垂直对齐,详情
    也就是使得本身和相邻元素对齐

  • flex 布局,似乎旧浏览器兼容不太好,但我觉得用着还行,太老的用户可以放弃了。设置 display:flex,然后 align-items:center。同上所述,使用 display 要注意连带影响。
  • 如果父容器高度可变的话,直接使 padding-toppadding-button 的值相等就好。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    <!--vertical-align的应用-->
    <div style="height:200px; background-color:yellow;display:table-cell;vertical-align:middle">
    <span style="font-size:20px;vertical-align:middle">文字</span>
    <img style="vertical-align:middle" src="logo.svg" width="100px;"/>
    <span style="font-size:40px;vertical-align:middle">文字</span>
    </div>
    <!--table方法-->
    <table style="height:200px;background-color:red;vertical-align:middle">
    <tr>
    <td>
    <p>文字</p>
    <img src="logo.svg" width="100px;"/>
    </td>
    </tr>
    </table>
    <!--flex方法-->
    <div style="height:200px; background-color:green;display:flex;align-items:center">
    <p>文字</p>
    <img src="logo.svg" width="100px;"/>
    </div>


  上图内容基于一条水平线对齐,就是 vertical-align:middle 的功劳


   对比上面两张图,flex 布局使得 <p> 标签没有独占一行。

  垂直居中的方法还有很多,如果能针对各种方法理出一个清晰的思路再来补充,目前觉得以上的够用~~就酱好累啊先不写了(  ̄︿ ̄)

-------------End of this article, thanks for your reading. -------------
奖励我一个棒棒糖吗?