一、場景描述
- 一個高度固定的div,做為父元素。
- 數個高度隨機的div,做為子元素,需要在父元素內被垂直居中。
二、相關概念回顧
1.幾種box
- inline box:display為inline或inline-block的元素會形成inline box;行內文本會形成inline box;
- line box:一行內所有的inline boxes會構成line box。其中inline box中高度最高的那個的高度便是line box的高度。
2.幾種line
- baseline(基線)
- ascendar height(上沿)
- descender height(下沿)
- x-height
另外還有line-height:對於塊級元素,它指定元素行盒(line box)的最小高度。對於非替代的inline元素,它用於計算行盒(line box)的高度。它是繼承屬性
更多解釋參見深入理解 CSS:字體度量、line-height 和 vertical-align
3. css屬性 vertical-align
參考MDN文檔可知:
CSS 的屬性 vertical-align 用來指定行內元素(inline)或表格單元格(table-cell)元素的垂直對齊方式。
使用場景
mdn文檔上是這樣描述的:
- to vertically align an inline element's box inside its containing line box. For example, it could be used to vertically align an
in a line of text.(設置一個inline元素的box相對於 包含它的line box 在垂直方向上的位置)
- to vertically align the content of a cell in a table(設置一個table中的一個cell的內容在垂直方向上的位置)
相關特性
- 初始值:baseline
- 適用元素:
- inline-level 元素
- table-cell 元素.
- ::first-letter and ::first-line.
- 是否是繼承屬性 否
- Percentages: refer to the line-height of the element itself(相對於該元素自己的line-height)
補充知識點:
::first-letter 會選中某 block-level element(塊級元素)第一行的第一個字母,並且文字所處的行之前沒有其他內容(如圖片和內聯的表格)
::first-line ::first-line CSS pseudo-element (CSS偽元素)在某 block-level element (塊級元素)的第一行應用樣式。
可能值
- baseline:Aligns the baseline of the element with the baseline of its parent.將該元素的baseline對准它父元素的baseline
- middle:Aligns the middle of the element with the baseline plus half the x-height of the parent.將該元素的baseline對准父元素的baseline + 1/2的x-heihgts
注意: 這些值雖然是相對於父元素而言的,但相對的僅僅是父元素中的一個line box。
三、實踐
1.Step1
代碼
html:
<body>
<div class="parent">
<div class="child1">
我是一號div 哈哈哈哈哈<br>哈哈哈哈哈哈
</div>
<div class="child2">
我是二號div
</div>
</div>
</body>
css:
.parent {
height:300px;
background-color: blue;
}
.child1 {
background-color: red;
display: inline-block;
}
.child2 {
background-color: yellow;
display: inline-block;
}
結果:
發現:
- 默認情況下,兩個為inline-block的子元素的vertical-align為baseline。
- 兩個inline-block的子元素的baseline在一條線上
- 兩個inline-block形成的兩個inline box組成的line box的高度是最高的的那個inline-box的高度,即一號div的高度
- vertical-align是相對於包含這些inline box的line box的位置的,而line box的高度、baseline、middle line的位置都是由最高的那個inline box決定的。
- 一號div也是由若干個line box構成(一行字就是一個line box)。一號div的baseline就是最后一個(最下面一個)的line box的baseline。那么二號的baseline是它的line box的baseline, 和一號div的baseline重合。同時它倆形成的line box的baseline也和它們各自的baseline都重合。
2.Step2
為了驗證上述3.可以將html修改一下(css不變)
代碼
<body>
<div class="parent">
<div class="child2">
二號div
</div>
<div class="child1">
一號div,啊啊啊啊啊啊啊啊啊啊<br>啊啊啊啊啊啊啊啊
</div>
</div>
</body>
css:同上
結果:
發現:
上述結論3.是對的,且可以得到:
- 所有inline box的baseline的位置是由最高的那個inline box的baseline的位置決定的。
3.Step3
我們知道vertical-align是相對於包含這些inline box的line box的位置的,而line box的高度、baseline的位置都是由最高的那個inline box決定的。那么真正的父元素,display為block的這個元素,有沒有baseline呢?答案是否定的。在inline-block元素處於block元素內部的情況下,它們兩個vertical-align決定的對齊策略針對的是同級的inline-block;也就是說它們的vertical-align造成的結果是它們自己的相互對齊,與父元素無關。
故現在試驗一下把父元素變為inline-block的結果。
代碼
html:同step1中的html代碼。
css:
.parent {
height:300px;
background-color: blue;
display: inline-block;
line-height: 300px;
}
.child1 {
background-color: red;
display: inline-block;
}
.child2 {
background-color: yellow;
display: inline-block;
}
結果:
此時父元素是inline-block且line-height為300px。由於line-height是繼承的,所以兩個子元素的line-height也是300px。
另外,由於父元素變成了inline-block,所以其寬度不再自動是body的100%,其寬度變成了由內容決定。(這又涉及到另一個問題:父子元素尺寸繼承規律 參見我的另一篇博客)
發現:
- 當父元素是block時,vertical-align只與同級元素有關,和父元素無關——只和它們自己形成的一個line box有關。
- 當父元素是inline-box時,vertical-align和父元素的line-height相關。
4.Step4
實現垂直居中。
既然這些inline-block只和同級元素有關,那么就創建一個高度等於父元素的同級inline-block。然后由於這個高度等於父元素的同級元素是這些inline-block中最高的,故由這些inline box組成的line box的baseline、x-height的位置都由該高度等於父元素的inline-block決定。
代碼
html:同step1中的html代碼。
css:
.parent {
height:300px;
background-color: blue;
}
.parent::before {
display: inline-block;
height: 100%;
content: '';
vertical-align: middle;
}
.child1 {
background-color: red;
display: inline-block;
vertical-align: middle;
}
.child2 {
background-color: yellow;
display: inline-block;
vertical-align: middle;
}
結果
5.Step5
為了更深入地也就vertical-align,現在在Step4的基礎上,將幾個inline-block的vertical-align分別進行修改。
代碼
html:同step1中的html代碼。
css:
.parent {
height:300px;
background-color: blue;
}
.parent::before {
display: inline-block;
height: 100%;
content: '';
vertical-align: middle;
}
.child1 {
background-color: red;
display: inline-block;
}
.child2 {
background-color: yellow;
display: inline-block;
vertical-align: middle;
}
結果
給上述child1增加屬性:vertical-align:top 結果如下:
發現
- 每個inline-block都要自己設置vertical-align來決定自己的位置,否則自己的位置就在baseline上。
- 必須設置基准inline-block的vertical-align為middle。
參考資料
http://zxc0328.github.io/2015/07/23/vertical-align-middle/
https://zhuanlan.zhihu.com/p/25808995
https://developer.mozilla.org/zh-CN/docs/Web/CSS/vertical-align