天天看點

CSS世界Bug般的存在——字母x與“居中”

字母x ?

《css世界》中提到:“我們這裡的字母x就是26個英文字母中的x。由于自身形态的一些特殊性,這個小小的不起眼的字母擔當大任,在css世界中扮演了一個重要的角色。”

筆者在這兩天寫一個項目中遇到了“居中”的困惑:我發現代碼段

li{
  verticle-align: middle;
}      

失效!

經過一番查證,發現:vertical-align屬性隻對行内元素有效,對塊元素無效

但我很快想到:有時候為什麼寫了line-height也會出錯、或者說反而會出錯呢?

有時使用display:inline-block會導緻verticle-align:middle失效。為何?因為display:inline-block會導緻line-height有偏差

這又是什麼原理?

CSS世界Bug般的存在——字母x與“居中”

字母x與“基線”

在各種内聯相關模型中,凡是涉及垂直方向的排版或者對齊的,都離不開最基本的——基線。

例如,​

​line-height​

​​行高的定義就是兩基線的間距,​

​verticle-align​

​的預設值就是基線;其它中線頂線一類的定義也離不開基線。

基線也延伸出了很多其它的概念:

比如字母基線、懸挂基線、表意基線

CSS世界Bug般的存在——字母x與“居中”

而【基線】的定義就離不開本文的主角“X”。

字母x的下邊緣(所在直線)就是我們所說的基線

上面所說内容當然和開頭的“問題”沒有直接關系,但是它确實引出了下面的一系列概念:

CSS世界Bug般的存在——字母x與“居中”

字母x與CSS中的x-height

要更深層次的了解字母x,或者說基線與居中有何關系,那就不得不說CSS中的一個概念——x-height

它指的是字母x的高度!

通俗的講,x-height就是指小寫字母x的高度,術語描述就是基線和等分線(也叫“中線”)之間的距離:

CSS世界Bug般的存在——字母x與“居中”

為什麼要說這個?

CSS中有些屬性值的定義其實就和這個​​

​x-height​

​​有關,最典型的代表就是​

​verticle-align: middle;​

​​。這裡的middle是中間的意思。注意:跟上面所說【中線】不是一個意思(圖中baseline上面那根就是median——中線)。

在CSS中,middle指的是基線往上1/2 x-height高度的位置。我們可以近似了解為“字母x的交叉點所在位置”。

由此可見,​

​verticle-align: middle​

​ 并不是絕對的垂直居中對齊 —— 我們平時看到的middle效果隻是一種近似效果。原因很簡單:不同字型在行内盒子中的位置是不一樣的。

事實上,“微軟雅黑”是一個字元比較下沉的字型——所有字元的位置都比其它字型要偏下一點。

也就是說,“微軟雅黑”字型中的字母x的交叉點是在容器中分線的下面一點。而此時我們就不難了解為什麼verticle-align不是相對容器的中分線對其的了。

讓我們回到開頭的一段代碼,我們此時可以很容易想到:先将其變為行内

li{
  display: inline-block;
  verticle-align: middle;
}      

發現沒啥用。。。

然後我們“恍然大悟”,想到:這是缺少“參照”的表現啊!

而對于li清單,适合用什麼布局呢?——table:

li{
  display: table-cell;   /* 轉化為單元格 */
  verticle-align: middle;
}      
其實line-block失效的原因有很多:比如你再元素外層又包裹了div,對div設定display、本來就是line…這裡是恰好碰上li罷了

這樣就解決了。

CSS世界Bug般的存在——字母x與“居中”

字母x與CSS中的ex

我們可能都聽過em、rem、px、rpx,但是這個ex是什麼鬼。。。

說起這個,他可能就會很自豪:畢竟是連IE6都支援的屬性機關。

ex是CSS中的一個相對機關,指的就是小寫字母x的高度。沒錯,就是指x-height。

而且——不受字型和自号影響的内聯元素的垂直居中對其效果!

我們都知道,内聯元素預設是基線對齊的,而基線就是x的底部,而1ex就是一個x的高度。設想一下,假如圖檔(标)的高度就是1ex,将其作為背景圖檔顯示,這時如果(背景)圖檔居中,那豈不是圖示和文字“天然”垂直居中對齊?而且不受字型和自号的影響。

<div class="mxc">
  yunxiaomeng<i class="icon-arrow"></i>
</div>
<style>
  .icon-arrow {
      display: inline-block;
      width: 20px;
      height: 1ex;
      background: url("/img/up.png") no-repeat center/20px 20px;
  }
</style>      

然後就對齊了 —— 完全沒有verticle-align的出場機會嘛!

li:after{
  content: "";
  display: inline-block;
  height: 100%;
  vertical-align: middle;
}