面試的時候,絕不能只說一種,絕不能說一種解決方案,絕不能停下你吞吞吐吐的嘴
CSS 方面問的最多的問題之一,我想分三種情況,水平居中、垂直居中和水平垂直居中來分析
單單就水平垂直居中而言,大概有以下幾種方案:
居中元素不定寬高
- absolute + transform
- flex 屬性居中
- flex + 子項 margin auto
- grid 屬性居中
- grid + 子項 margin auto
- grid + 子項屬性居中
- -webkit-box 屬性居中
- table-cell + text-align
- line-height + text-align
- writing-mode
- table
僅居中元素定寬高適用:
- 須知寬高 + absolute + 負 margin
- 須知寬高 + absolute + calc
- 須知寬高 + absolute + margin auto
侷限性較大的全域性居中
- 須知寬高 + fixed + transform
- 須知寬高 + fixed + 負 margin
- 須知寬高 + fixed + calc
- 須知寬高 + fixed + margin auto
水平居中
text-align: center
text-align: center;
需設定 display: inline-block
行內塊元素
絕對定位 + transform 位移
position: absolute;
left: 50%;
transform: translateX(-50%);
脫離文件流
寬度+ margin: 0 auto
width: 100px;
margin: 0 auto;
這裡說明下,width:100px
必須是具體的數字,且這個居中是外層居中,寬度中的內容沒有居中
垂直居中
絕對定位 + transform 位移
position: absolute;
top: 50%;
transform: translateY(-50%);
與水平方向的居中一樣,都是脫離文件流的做法
table-cell + vertical-align
display: table-cell;
vertical-align: middle;
display: table-cell
,讓其標籤元素以表格單元格的形式呈現,類似於 td
標籤,
vertical-align: middle
,用來指定行內元素(inline)或表格單元格(table-cell)元素的垂直居中
水平垂直居中
絕對居中 + transform 位移
<div class="father">
<div class="son">
123123
</div>
</div>
.father {
position: relative;
}
.son {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
flex 屬性居中
<div class="father">
<div class="son">
123123
</div>
</div>
.father {
display: flex;
justify-content: center;
align-items: center;
}
flex + margin auto
<div class="father">
<div class="son">
123123
</div>
</div>
.father {
display: flex;
}
.son {
margin: auto;
}
grid 屬性居中
<div class="father">123123</div>
// 或者
<div class="father">
<div class="son">
123123
</div>
</div>
.father {
display: grid;
justify-content: center;
align-items: center;
}
grid 子項屬性居中
<div class="father">
<div class="son">
123123
</div>
</div>
.father {
display: grid;
}
.son {
align-self: center;
justify-self: center;
}
grid + margin auto
<div class="father">
<div class="son">
123123
</div>
</div>
.father {
display: grid;
}
.son {
margin: auto;
}
grid 和 flex 很像,是 flex 的升級版,所以 grid 能做的事情更多
以上絕對定位、flex、grid 關於水平垂直居中的做法,剩下再說居中比較老的佈局方法
-webkit-box 屬性居中
這是一個已經過時的佈局,可以看看這篇文章 CSS3 display: flex 和 display: box 有什麼區別?
網友一絲說:
flex 是 2012 年的語法,是以後的標準
box 是 2009 年的語法,已經過時,需要加上對應字首
<div class="father">
<div class="son">
123123
</div>
</div>
.father {
display: -webkit-box;
-webkit-box-pack: center;
-webkit-box-align: center;
}
table-cell + text-align
<div class="father">
<div class="son">
123123
</div>
</div>
.father {
display: table-cell;
vertical-align: middle;
text-align: center;
}
.son {
display: inline-block;
}
line-height + text-align
<div class="father">
<div class="son">
123123
</div>
</div>
.father {
height: 200px;
line-height: 200px;
text-align: center;
}
line-height
與 height
,行高和高度一樣高,自然就垂直方向居中了
writing-mode
<div class="father">
<div class="“son”">
<div class="“sonson”">
123123
</div>
</div>
</div>
.father {
writing-mode: tb-lr;
writing-mode: vertical-lr;
text-align: center;
}
.father .son {
writing-mode: lr-tb;
writing-mode: horizontal-tb;
text-align: center;
width: 100%;
display: inline-block;
}
.father9 .son .sonson {
display: inline-block;
text-align: initial;
}
這個很冷悶,有人介紹過這種情況
table
<table>
<tbody>
<tr>
<td class="father">
<div class="son">
123123
</div>
</td>
</tr>
</tbody>
</table>
.father {
text-align: center;
}
table 標籤自己將它垂直居中了,text-align:center
後就是水平居中了
可以看 demo
當元素有寬高的情況,又多了三種方案
須知寬高 + 絕對居中 + margin 負邊距
<div class="father">
<div class="son">
123123
</div>
</div>
.father {
position: relative;
height: 200px;
}
.son {
width: 100px;
height: 100px;
position: absolute;
top: 50%;
left: 50%;
margin: -50px 0 0 -50px;
}
父元素必須要有個高度,這樣才能撐開容器。子元素必須要有個寬高,才能計算出 margin 值
須知寬高 + 絕對定位 + calc
<div class="father">
<div class="son">
123123
</div>
</div>
.father {
position: relative;
height: 200px;
}
.son {
width: 100px;
height: 100px;
position: absolute;
top: calc(50% - 50px);
left: calc(50% - 50px);
}
與 margin 負邊距一個道理,父元素需要設定一個高度。子元素必須要有高度,不用 margin,而用 CSS3 中的 calc,計算出要居中位移,相容性需要支援 CSS3 屬性
須知寬高 + 絕對居中 + margin: auto
<div class="father">
<div class="son">
123123
</div>
</div>
.father {
position: relative;
height: 300px;
}
.son {
width: 100px;
height: 100px;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
}
同以上兩種情況。
這三種需要定位方式來實現水平垂直居中的方法,需要設定父元素的高度(一定要有,撐開畫面),子元素需要設定寬高,前兩種方法是為了算出它在父元素中的相對位置,後一種方法是為了說明子元素是個容器(如果不設定寬高,就是無)
其他方法
其實,水平垂直居中方面,如果面試官硬要問還有嗎?還真的有,用 fixed 定位。但這個方法有缺陷,雖然能實現水平垂直居中,但它是相對於視口(viewport),而非父元素
方法就是以上用 absolute 實現的改成 fixed 即可
- 須知寬高 + fixed + transform
- 須知寬高 + fixed + 負 margin
- 須知寬高 + fixed + calc
- 須知寬高 + fixed + margin auto
這四種方法,都需要設定子元素的寬高
這裡貼一下程式碼
<div class="father">
<div class="son">
123123
</div>
</div>
/* transform */
.son {
width: 100px;
height: 100px;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: blue;
}
/* 負 margin */
.son {
width: 100px;
height: 100px;
position: fixed;
top: 50%;
left: 50%;
margin-left: -50px;
margin-top: -50px;
background: blue;
}
/* calc */
.son {
width: 100px;
height: 100px;
position: fixed;
top: calc(50% - 50px);
left: calc(50% - 50px);
background: blue;
}
/* margin: auto */
.son {
width: 100px;
height: 100px;
position: fixed;
top: 0;
left: 0;
bottom: 0;
right: 0;
margin: auto;
background: blue;
}
總結
隨著微軟宣佈放棄 IE11,現實專案中完全可以使用 flex 佈局,grid 部分還不適配,但是以後肯定會取代 flex。
雖然寫了很多,但是自己工作中也不會使用 table 、writing-mode、-webkit-box 等過時的佈局方式,寫這篇文章,純粹是為了面試時被問到這種問題。
收穫是 absolute 的居中要父子同心(父元素設定高度,子元素設定寬高),fixed 的居中只需要設定子元素的寬高。
線上 demo 檢視
參考資料
本文參與了 SegmentFault 思否徵文「如何“反殺”面試官?」,歡迎正在閱讀的你也加入。