29. CSS 水平置中/ 垂直置中的方法

首先,预设范例的层级关系是这样:

<!-- HTML -->
<div class="parent translate">
    <div class="child"></div>
</div>

<div class="parent">
    <h1 class="text">Hello</h1>
</div>

这里预设了区块置中文字置中两种情况。

/* CSS */
.parent{
  background: gray;
  width: 100%;
  height: 300px;
}

.child {
  background: blue;
  width:100px;
  height:100px;
}

目前会长成这样子:
https://ithelp.ithome.com.tw/upload/images/20211011/20129476bh4ZFTIlBl.png

1. Flexbox


第一个方法是: 在父容器上套用flex进行操作。

flex的概念是 会有一个容器(container)包住物件(item),然後可以控制内部物件的排版方式。
所有的 内容物(item) 都是 弹性物件(flex item)。

( 相关说明和图解可以参考: A Complete Guide to Flexbox )

flexbox垂直置中的方法,是在container加上置中的控制项,
以范例来说就是加在.parent

.parent {
  display: flex;
  /* 水平置中 */
  justify-content: center;    
  /* 垂直置中 */
  align-items: center;        
}

其中align-items: center;也可以用这两行替换,效果一样:

.parent {
  display: flex;
  /* 水平置中 */
  justify-content: center;    
  /* 垂直置中 */
  align-content: center;      
  flex-wrap: wrap;
}
  • align-content
    • 决定在多行情况下,items垂直方向的分布情形。(对只有一行的items无效)
    • flex-wrap: nowrap;的情况下无效,所以在这里要再加上flex-wrap
  • flex-wrap
    • nowrap(预设值)会将所有的flex items压缩在同一行。
    • 设值为wrap,则不会压缩items,如果items过多就换行。

执行结果:
https://ithelp.ithome.com.tw/upload/images/20211011/20129476ahV1yQGuzo.png

这个方法,item不论是文字(<p><h1>、...)或区块(<div>)都可以用,是我自己最常使用的方法。
https://ithelp.ithome.com.tw/upload/images/20211011/201294769N9EBHqQiJ.png

缺点是相容性问题,IE6~9、Opera10~11.5都不支援flex。

2. 相对定位 + transform


第二个方法,是在要置中的元素(.child)加上相对定位。

.child {
  position: relative;
  top: 50%;  
  left: 50%;
  transform: translate(-50%, -50%);
}
  • position
    • css的布局是将一个个box排进flow里,而设值relative可以 使元素在不被flow排除的情况下 ,以所在位置为基准,进行偏移。
  • top/ left
    • 垂直置中等於,距离上半部50%,这里的百分比是基於容器的宽度。
    • 水平置中则等於向左方偏移50%。
  • transform
    • 因为css预设的物件,基准点是向左上方靠齐,如果没有调整translate,会发现水平和垂直方向,都会超过中心。
    • translateX(水平方向) = -50%,会向左平移物件宽度的50%,translateY则是控制垂直方向上移。可以想成加入这一行才会把基准点移到物件的中心。

执行结果:
https://ithelp.ithome.com.tw/upload/images/20211011/20129476Eb8zJ7fOFn.png

<div>的情况上没什麽问题,但会发现文字水平方向位置不对:
https://ithelp.ithome.com.tw/upload/images/20211011/20129476GnpDZLZxzW.png

其实可以用更简单一点的方法控制文字的水平置中:

.parent {
  text-align: center;  // 文字水平置中
}

.text {
  position: relative;
  top: 50%;
  transform: translate(0, -50%);
}
  • text-align: center;加在文字上也有效。(但概念上我觉得加在父容器上比较好。)
  • 然後记得translateX(水平方向)不需要调整,但translateY(垂直方向)依然需要调整基准点,不然会偏移(靠下)。

这样就成功了!
https://ithelp.ithome.com.tw/upload/images/20211011/20129476ebnxhIAFna.png

!!然而,缺点是IE6~8依然不支援transform。

3. 绝对定位


第三个方法是设定child为 以parent为基准的绝对定位。

.parent {
  position: relative;
}

.child {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  margin: auto;
}
  • position: absolute
    • CSS的绝对定位会将box移出flow,偏移的位置预设会以整个网页(视窗)为基准,或是以设为position: relative;的父层为基准。
      因为这里还需要依赖.parent的位置进行偏移,所以要在.parent设定relative

这个方法就比较没有相容性的问题,
缺点是,像文字不具宽高的元素会无法使用。

文字的处理方法

在这里可以尝试加入伪元素来处理,

可以想像成文字前多了一个看不到的元素,

.parent {
  text-align: center;  // 文字水平置中
}

.parent:before {
  content: "";
  display: inline-block;
  height: 100%;    // block才有高度
  vertical-align: middle;    // 对inline有效,垂直置中对齐
}

.child {
  display: inline-block;   // 设定inline也可以
}
  • content: ""; content内容为空,因为伪元素是辅助用,实际上不会看到这个元素。
  • display: inline-block; 是为了确保,能设定高度和parent相同(100%),且同时设定vertical-align是置中。

虽然正解长得都一样,但还是放一下成功的结果:
https://ithelp.ithome.com.tw/upload/images/20211011/20129476GhkbrFiR8U.png

附上 codepen完整程序码

【如内文有误还请不吝告知>< 谢谢阅览至此的各位:D】

参考资料:

-----正文结束-----

方法有很多,我觉得自己记得起来,和大部分情境都可以使用是最重要的。


<<:  Day26 - 收放工具按钮

>>:  Day28 - 如何埋 GA (Google Analytics)

GitHub Action 实作持续交付 - 常见代理程序架构与部署至 IIS

透过前一篇文章的介绍,读者应该了解现今的云端服务相当方便,许多持续交付的功能已经写成 Action,...

Vue [笔记] Dom元素无生成完毕、API来不及抓取之处理、传值方式

1. Dom元素无生成完毕,使用this.$nextTick 情境:Dom元素无生成 导致 refs...

Day 29: 人工智慧在音乐领域的应用 (卢森堡-AIVA)

今天作为这系列的结尾,我们来详细介绍这家位於卢森堡的新创公司AIVA的AI作曲服务。 AIVA AI...

[Day18] - Django-REST-Framework API 呼叫及介面操作

昨天我们使用 DRF 实作出了第一个 API -- 商品查询 API 。相信大家都有感到成就感吧!以...