iT邦幫忙

2021 iThome 鐵人賽

0
自我挑戰組

登堂入室!前端工程師的觀念技術 _30_ 題系列 第 30

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】

參考資料:

-----正文結束-----

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


上一篇
28. 解釋 CSS Box Model ( box-sizing )
下一篇
30. CSS 的 z-index & Stacking Context 的形成
系列文
登堂入室!前端工程師的觀念技術 _30_ 題31

尚未有邦友留言

立即登入留言