最近處理了一個字體圖標沒有在容器中垂直居中的樣式問題。本來覺得,只是 css 寫的不正確,實際卻並無那麼簡單。
一番波折後,最終發現,是由於一處小細節,挖出了個大坑。
在處理問題的整個過程當中,一方面複習了相關的 css 基礎知識;另外一方面,對於問題緣由的推理方法上,也給了我一些新的啓示,故特此記錄下來。css
同事小 w 請教了我一個樣式問題:他寫的頁面上,一處本該垂直居中的字體圖標,變成了與容器頂部對齊,不知道是哪裏 css 寫的不對,
如圖所示(因爲事故現場已不存在,此處爲模擬還原的場景): html
<div class='wrapper'> <div class='inner'> <i class="far fa-check-circle"></i> </div> </div> 複製代碼
css 以下:瀏覽器
.outer { height: 60px; line-height: 60px; text-align: center; color: white; background-color: gray; } .inner { display: inline-block; font-size: 26px; line-height: 1; } 複製代碼
能夠看到,html 結構很簡單,分爲三部分,即外部容器.outer
,內部容器.inner
,以及字體圖標自己。
外部容器將height
於line-height
同設爲 60px,是經典的垂直居中的方法,然而,結果卻並無實現居中。
問題出在哪裏了呢?
那麼就先從垂直居中的原理來分析一下吧。markdown
咱們常常說,「讓height
等於line-height
能夠實現垂直居中」。其實,這個說法自己,是有很多問題的。
首先,對於一個容器和一個內聯元素來講,並不須要同時設置height
和line-height
,只要給容器設置line-height
,就能夠「垂直居中」了,以下圖: app
<div class='wrapper'> <span class='text'>中文文本</span> </div> 複製代碼
.wrapper { margin-bottom: 20px; line-height: 100px; color: white; background-color: gray; text-align: center; } 複製代碼
不須要設height
很好理解,由於line-height
也能夠將容器高度撐開,此時的height
的值爲auto
,自動計算成了line-height
的值。
之因此會有「讓height
等於line-height
」的說法,是由於最先這種作法是基於高度已經固定的容器,要使得其中的文本垂直居中,就須要設置容器的line-height
等於高度。(因此也能夠直接去掉高度,改成設置line-height
)
但這裏還有個問題,其實文本並無真正的「垂直居中」,確切的說,是文本的「內容區域」居中了。若是給文本設置背景色,就能夠看出其內容區域: 字體
display: inline-block
的元素來講,是不存在的。以下圖:
<div class='wrapper'> <span class='cube'></span> </div> 複製代碼
.wrapper { margin-bottom: 20px; line-height: 100px; color: white; background-color: gray; text-align: center; } .cube { display: inline-block; width: 50px; height: 50px; background-color: white; } 複製代碼
對於display: inline-block
的元素,要使其垂直居中,咱們一般會在元素上添加vertical-align: middle
使其垂直居中,如圖: ui
.wrapper { margin-bottom: 20px; line-height: 100px; color: white; background-color: gray; text-align: center; } .cube { display: inline-block; width: 50px; height: 50px; background-color: white; vertical-align: middle; } 複製代碼
這是什麼原理呢?
參考 w3c 對於vertical-align
的定義,當設置爲middle
時:spa
Align the vertical midpoint of the box with the baseline of the parent box plus half the x-height of the parent.翻譯
翻譯過來,就是說,vertical-align: middle
的元素,會和父元素所用字體的 baseline 高度加上 x-height 的一半對齊,而這個值,其實就是小寫字母 x 的中線的高度,如圖: 設計
vertical-align
,即
vertical-align: baseline
時,爲何元素會偏高:
vertical-align: baseline
的定義:
Align the baseline of the box with the baseline of the parent box. If the box does not have a baseline, align the bottom margin edge with the parent's baseline.
因此,元素塊的底部,與 baseline 對齊,也就是字母 x 默認所處位置的那條線:
完成了以上的分析,再回頭看最開始的問題,發現,做爲內容器做爲display: inline-block
元素,沒有添加vertical-align
屬性,因而咱們加上它試試:
.wrapper { height: 60px; line-height: 60px; text-align: center; color: white; background-color: gray; } .inner { display: inline-block; font-size: 26px; line-height: 1; vertical-align: middle; } 複製代碼
發現並無用。難道是由於只有一個字體圖標,沒有一個參照物的緣由?(以前的中文字符不止一個字)
帶着這種設想,在字體圖標旁,添加一個字符試試,以下:
The minimum height consists of a minimum height above the baseline and a minimum depth below it, exactly as if each line box starts with a zero-width inline box with the element's font and line height properties. We call that imaginary box a "strut." (The name is inspired by TeX.).
以及在vertical-align
段落中寫道:
The following values only have meaning with respect to a parent inline element, or to the strut of a parent block container element.
簡而言之,當只有一個字符時,瀏覽器會在文本前,設置一個 0 寬度的隱藏字符,做爲對齊的參考。因此說,並不須要去手寫一個字符來對齊。
這下,我凌亂了。。。
冷靜一下後,繼續開始分析。發現,不一樣頁面上,html 結構和 css 是徹底一致的,但爲何實際樣式會不同呢?
再根據以上的理論分析,發現沒有居中的緣由,極可能是瀏覽器沒有提供這樣一個strut
,做爲參考。而這,並不符合 w3c 定義的規範。
想到這裏,忽然意識到了什麼,在對比一下頁面,發現了惟一一處不一樣點:
<!DOCTYPE html>
,這下問題終於解決了。
首先,對於垂直居中問題,利用line-height
未必能實現,這個須要根據具體狀況來分析,而分析的依據,正是 w3c 中的基本定義。因而可知,對於基礎概念,不該當只停留在會用的階段,仍是須要完整的閱讀一遍,理解透徹; 其次,對於排查問題,除告終合理論依據外,嘗試作對比是一個很好的方式。經過對比,一步步排除不相關緣由,最後就能挖出問題所在; 最後,在排查的過程當中,決不能無憑無據預設條件。由於在此次,糾結了好久的一個緣由,正是由於沒有考慮到,頁面的標準自己存在問題,而把時間花在尋找使用方式上是否是還存在未知錯誤。直到後來,一步步排除了以後,才鎖定到了最終緣由。