點燈坊

失くすものさえない今が強くなるチャンスよ

如何垂直置中 ?

Sam Xiao's Avatar 2021-04-04

垂直置中為實務上常見需求,CSS 可由多種方式實現。

Version

CSS 3

Flexbox

justify-content: space-between

center003

Flexbox 亦有多種方式可垂直置中,先討論從父層 box 處理。

<template>
  <div class="box">
    <div/>
    <div>CSS</div>
    <div/>
  </div>
</template>

<style scoped>
.box {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  height: 100vh;
}
</style>

第 2 行

<div class="box">
  <div/>
  <div>CSS</div>
  <div/>
</div>

子層使用 3 個 item,兩旁為 dummy div。

10 行

.box {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  height: 100vh;
}

設定父層 box style:

  • display: flex:子層 item 使用 Flexbox 排列
  • flex-direction: column:設定 main axis 為 column
  • justify-content: space-between:原本為將剩餘高度自動平分給 item 間剩餘空間,因為兩側 dummy div 沒有高度,平分剩餘空間後 CSS 看起來像垂直置中
  • height: 100vh: 設定 box height

justify-content: space-around

center004

CSS 垂直置中,一樣使用 justify-content 系列。

<template>
  <div class="box">
    CSS
  </div>
</template>

<style scoped>
.box {
  display: flex;
  flex-direction: column;
  justify-content: space-around;
  height: 100vh;
}
</style>

第 8 行

.box {
  display: flex;
  flex-direction: column;
  justify-content: space-around;
  height: 100vh;
}

設定父層 box 的 style:

  • display: flex:子層 item 使用 Flexbox 排列
  • flex-direction: column:設定 main axis 為 column,也因為 main axis 為 column,本來 Flexbox 會使 <div> 寬度由 content 決定,高度撐滿 100vh,現在改成高度由 content 決定,高度撐滿一整列
  • justify-content: space-around:原本與 space-between 一樣將剩餘高度自動平分給 item 間剩餘空間,但不同的是 space-around 會考慮 item 的前後空間,因此平分後看起來 CSS 像垂直置中

justify-content: space-evenly

center005

CSS 垂直置中,一樣使用 justify-content 系列。

<template>
  <div class="box">
    CSS
  </div>
</template>

<style scoped>
.box {
  display: flex;
  flex-direction: column;
  justify-content: space-evenly;
  height: 100vh;
}
</style>

第 8 行

.box {
  display: flex;
  flex-direction: column;
  justify-content: space-evenly;
  height: 100vh;
}

設定父層 box 的 style:

  • display: flex:子層 item 使用 Flexbox 排列
  • justify-content: space-evenly:原本與 space-between 一樣將剩餘高度自動平分給 item 間剩餘空間,但不同的是 space-evenly 會考慮 item 的前後空間,因此平分後 CSS 看起來像垂直置中

space-aroundspace-evenly 差異是儘管包含 item 前後空間,但 space-evenly 是真正 evenly 等高,但 space-around item 間空間會是前後高度的兩倍

justify-content: center

center000

CSS 垂直置中,一樣使用 justify-content 系列。

<template>
  <div class="box">
    CSS
  </div>
</template>

<style scoped>
.box {
  display: flex;
  flex-direction: column;
  justify-content: center;
  height: 100vh;
}
</style>

第 8 行

.box {
  display: flex;
  flex-direction: column;
  justify-content: center;
  height: 100vh;
}

設定父層 box 的 style:

  • display: flex:子層 item 使用 Flexbox 排列
  • flex-direction: column:設定 main axis 為 column,也因為 main axis 為 column,本來 Flexbox 會使 <div> 寬度由 content 決定,高度撐滿 100vh,現在改成高度由 content 決定,寬度撐滿一整列
  • justify-content: center:直接將 <div> 置中於 main axis,因為目前 main axis 為 column,相當於垂直置中
  • height: 100vh:設定 box height

align-items: center

center001

CSS 垂直置中,改用 align-items 系列。

<template>
  <div class="box">
    CSS
  </div>
</template>

<style scoped>
.box {
  display: flex;
  align-items: center;
  height: 100vh;
}
</style>

第 8 行

.box {
  display: flex;
  align-items: center;
  height: 100vh;
}

設定父層 box 的 style:

  • display: flex:子層 item 使用 Flexbox 排列
  • align-items: center:由於沒更改 flex-direction,因此目前 main axis 仍是 row,可使用 align-items: center 直接置中於 cross axis,相當於垂直置中
  • height: 100vh:設定 box height

align-content: center

center006

CSS 垂直置中,改用 align-content 系列。

<template>
  <div class="box">
    CSS
  </div>
</template>

<style scoped>
.box {
  display: flex;
  flex-wrap: wrap;
  align-content: center;
  height: 100vh;
}
</style>

第 8 行

.box {
  display: flex;
  flex-wrap: wrap;
  align-content: center;
  height: 100vh;
}

設定父層 box 的 style:

  • display: flex:子層 item 使用 Flexbox 排列
  • flex-wrap:啟動換列機制,會抑制 align-items: stretch 預設 stretch 整個父層 box 高度,僅收縮成與 content 同高,因此 flex line 也收縮不再與父層 box 同高
  • align-content: center:因為 flex line 不再與父層 box 同高,因此 align-content: center才有機會以 flex line 對父層 box 垂直置中
  • height: 100vh:設定 box height

flex-grow: 1

center002

CSS 垂直置中,但在子層 item 處理。

<template>
  <div class="box">
    <div class="empty"/>
    <div>CSS</div>
    <div class="empty"/>
  </div>
</template>

<style scoped>
.box {
  display: flex;
  flex-direction: column;
  height: 100vh;
}

.empty {
  flex-grow: 1;
}
</style>

第 2 行

<div class="box">
  <div class="empty"/>
  <div>CSS</div>
  <div class="empty"/>
</div>

需使用三個子層 item。

10 行

.box {
  display: flex;
  flex-direction: column;
  height: 100vh;
}

設定父層 box 的 style:

  • display: flex:子層 item 使用 Flexbox 排列
  • flex-direction: column:設定 main axis 為 column
  • height: 100vh:設定 box height

16 行

.empty {
  flex-grow: 1;
}
  • flex-grow: 1:表示空白部分剩餘 height 將由此 <div> 平分,因此看起來為垂直置中

Fixed Position

center007

CSS 垂直置中,但使用 fixed position 處理。

<template>
  <div class="box">
    CSS
  </div>
</template>

<style scoped>
.box {
  height: fit-content;
  position: fixed;
  top: 0;
  bottom: 0;
  margin: auto;
  outline: 1px solid black;
}
</style>

第 8 行

.box {
  height: fit-content;
  position: fixed;
  top: 0;
  bottom: 0;
  margin: auto;
  outline: 1px solid black;
}

設定父層 box style:

  • height: fit-content:height 與 content 同高,但仍維持其 block 特性,讓 margin: auto 有操作空間
  • position: fixed:使用 fixed position
  • top: 0bottom: 0:要使用 margin: auto 垂直置中,前提必須要有空間使其調整 margin,top: 0 於上側邊緣緊貼 browser,bottom: 0 於下側邊緣緊貼 browser,因此相當於架構出無形的矩形空間,只是受限於 height: fit-content 只顯示與 content 同高部分,剩下空間可由 margin: auto 自由發揮而垂直置中
  • margin: auto:自動調整上下 margin 而垂直置中
  • outline: 1px solid black:為了視覺顯示方框,實務上可不使用

Absolute Position

center008

CSS 垂直置中,但使用 absolute position 處理。

<template>
  <div class="box">
    CSS
  </div>
</template>

<style scoped>
.box {
  height: fit-content;
  position: absolute;
  top: 0;
  bottom: 0;
  margin: auto;
  outline: 1px solid black;
}
</style>

第 8 行

.box {
  height: fit-content;
  position: absolute;
  top: 0;
  bottom: 0;
  margin: auto;
  outline: 1px solid black;
}

設定父層 box style:

  • height: fit-content:height 與 content 同高,但仍維持其 block 特性,讓 margin: auto 有操作空間
  • position: absolute:使用 absolute position,因為其父層皆沒設定定位,相當於定位在 window
  • top: 0bottom: 0:要使用 margin: auto 垂直置中,前提必須要有空間使其調整 margin,top: 0 於上側邊緣緊貼 browser,bottom: 0 於下側邊緣緊貼 browser,因此相當於架構出無形的矩形空間,只是受限於 height: fit-content 只顯示與 content 同高部分,剩下空間可由 margin: auto 自由發揮而垂直置中
  • margin: auto:自動調整上下 margin 而垂直置中
  • outline: 1px solid black:為了視覺顯示方框,實務上可不使用

Relative Position

center000

CSS 垂直置中,改由父層 box 使用 relative position 處理。

<template>
  <div class="box">
    <div class="item">
      CSS
    </div>
  </div>
</template>

<style scoped>
.box {
  position: relative;
  height: 100vh;
}
</style>

第 2 行

<div class="box">
  <div class="item">
    CSS
  </div>
</div>

需使用兩層 HTML。

10 行

.box {
  position: relative;
  height: 100vh;
}

設定父層 box style:

  • position: relative:父層 box 使用 relative position,子層 absolute position 將以此層定位
  • height: 100vh:設定 height 為整個 browser 高度

水平置中時不必設定 width,因為 block 預設就是佔據一整列,但 height 預設只是 content 高度,因此要特別設定才能垂直置中

15 行

.item {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
}

設定子層 item style:

  • position: absolute:子層 item 使用 absolute position
  • top: 50%top 座標為 50%,此為 item 上側位置,並不算垂直置中
  • transform: translateY(-50%):將 item 上移本身 height 的 50%,此時才算真正垂直置中

Conclusion

  • CSS 擁有多種方式垂直置中:Flexbox 、 Fixed Position 、 Absolute Position 與 Relative Position,可視實際需求靈活運用