深入理解行內元素的布局

前言

總括: 本文通過實例講解CSS中最大的難點之一剂公,行內元素的布局柠偶,主要是挖掘line-height和vertical-align兩個屬性在布局方面的使用稽莉。

白茶清歡無別事,我在等風塌西,也在等你谐宙。??

正文

講道理line-height和vertical-align 這對基是十分低調的烫葬,日常開發(fā)中碰到的很多莫名其妙的bug很大一部分都是這倆貨搞出來了的,但很少有人知道這對基的罪惡卧惜,因為可能花式改寫一下CSS代碼問題就解決了厘灼。實際上搞明白這倆東西才能讓我們在布局工作中游刃有余。本文接下來就通過這對基的關系來了解內聯元素具體的布局問題~we are刨根問底攔不住~??

? 讀這篇文章之前請確定您有以下知識基礎:

  • line-height的數字值是和font-size大小相關的咽瓷;
  • vertical-align的百分比值是和line-height值相關的设凹;

引出vertical-align

首先來看一個??:

<div class="test">
  ![](http://upload-images.jianshu.io/upload_images/1394123-beaa89c3197bcd45?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)<span>Xx</span>
</div>
.test {
    background: red;
}
img {
    width: 50px;
    height: 50px;
}
span {
    background: white;
}

下面無實例內容的話戳這里

<script async src="https://jsfiddle.net/Damonare/5oLvd0z4/embed/html,css,result/"></script>

? 如上代碼片段result所示,圖片下面有一明顯的紅色條條茅姜,??什么鬼闪朱,很詭異不是么,我要的是img充滿整個div啊!!!好吧钻洒,我加了一個額外的inline元素填寫內容Xx,發(fā)現原來多出來的那一塊正好是文字的下半空白部分奋姿。吆喝,這么巧素标?實際上称诗,如果將這里的Xx內容去掉,只剩下img头遭,那個條條依然存在寓免,表現行為好像父元素div里面除了img元素還有一個空白的元素一樣,??姑且叫它空白節(jié)點吧(肉眼中不存在卻在影響著布局)计维,這個是比較詭異的一個表現袜香,查標準沒找到有相關的說明。但請將這個空白節(jié)點先記住鲫惶,我們的重點是研究條條是咋出來的蜈首。這條條看上去貌似是文本和圖片垂直方向上對齊生成的,那么這就引粗來一個問題欠母,inline元素默認的垂直方向的對齊方式是什么樣的欢策?也就是vertical-align的默認值是啥?

? OK赏淌,??I know you know猬腰。vertical-align默認值是baseline,OK猜敢,那就先來挖一挖vertical-align具體是個什么鬼锈拨。

Vertical-align(1)

vertical-align這個屬性我感覺是CSS中最復雜的屬性之一了...好多問題概念也讓人看不懂...一方面它是作用在inline元素和table-cell元素身上俏脊,屬性值特別多,另一方面該屬性規(guī)范里并沒有一個定論,導致一些屬性不同瀏覽器的實現也不同筏养,所以兼容性問題很多。對于一些 可替換元素孟辑,比如textarea山叮, HTML標準沒有說明它的基線,這意味著對其使用這個關鍵字博脑,各瀏覽器表現可能不一樣憎乙。我們這里先研究一下它的默認值baseline。

baseline字面意思就是基線叉趣,何為基線泞边?首先請記住下面這幾個概念:

  • 基線:小寫字母'x'的下邊緣所在的那條線;
  • x-height: 小寫字母'x'的高度;
  • ex: 1ex就是一個小寫字母'x'的高度疗杉,類似em單位阵谚,注意,ex和em都是相對單位;

我們看下CSS標準里怎么說的:相關標準鏈接

The baseline of an 'inline-block' is the baseline of its last line box in the normal flow, unless it has either no in-flow line boxes or if its 'overflow' property has a computed value other than 'visible', in which case the baseline is the bottom margin edge.

中文翻譯如下:

'inline-block'元素的基線是標準流中最后一個line box(行盒)的基線, 除非這個line box里面既沒有in-flow line boxes(行內框)或者本身’overflow’屬性的計算值不是’visible’, 這種情況下基線是該元素margin底邊緣烟具。

那么上面現象就很容易解釋的通了梢什,我們知道img元素默認的表現形式和inline-block元素一樣,它的基線就是margin底邊緣朝聋,而inline元素本身是有高度的嗡午,兩者基線對齊自然就如上面那樣表現了。??

??好吧冀痕,等會荔睹,到這里,我們發(fā)現實際又多了倆概念——inline元素的高度問題標準里說的line box(IFC)金度。

首先我們先來看下inline元素的高度問題应媚,即——line-height屬性。

Line-height

CSS中起高度作用的只有height和line-height兩個屬性吧猜极。如果一個元素沒設置height那么其最終的高度一定是由line-height決定的中姜。之前inline元素的高度我以為是文字內容撐開的,但實際研究了下并不是這樣的跟伏,看下面的??:

.demo1{
  font-size: 20px; 
  line-height: 0; 
  border: 1px solid blue; 
  background: red;
}
.demo2{
  font-size: 0; 
  line-height: 20px; 
  border: 1px solid red;
  background: yellow;
}

HTML代碼:

<div class="demo1">測試</div>
<div class="demo2">測試</div>

下面沒內容戳這或者自行拷貝代碼本地測試

<script async src="https://jsfiddle.net/Damonare/54ucnkht/embed/html,css,result/"></script>

如上可證明丢胚,inline元素的高度決定者是line-height,并不是文字內容撐開的受扳。??

CSS規(guī)范里對line-height的默認值有這么一句話:

We recommend a used value for 'normal' between 1.0 to 1.2.

只是推薦...??是不是說實際上各個瀏覽器對于line-height的默認值實現不一定是一樣的携龟,但都介于1.0-1.2之間。具體各大瀏覽器的實現值待查證勘高。這里需要記住line-height的默認值是啥就OK峡蟋。

IFC

在之前的博文CSS的盒子模型里面坟桅,有拓展過相關知識,簡短的介紹了下BFC和IFC蕊蝗,相較于BFC仅乓,IFC要復雜得多,規(guī)范里IFC的篇幅也要比BFC多得多蓬戚。

簡要總結下BFC夸楣,即塊級元素可能會觸發(fā)塊級格式上下文(BFC),在塊級格式上下文中子漩,塊級盒子豎直方向排列豫喧,不受上下文外部元素影響,自成一方世界幢泼。塊容器盒指的是那些包含元素的盒子紧显,塊容器盒可能包含其它塊級盒,也可能生成一個行內格式上下文(IFC)旭绒。??

但塊容器盒要么只包含行內盒鸟妙,要么只包含塊級盒。但通常會同時包含兩者挥吵。在這種情況下重父,將創(chuàng)建匿名塊盒來包含毗鄰的行內級盒。

看個??:

//demo1
<div>
  Some inline text 
  <p>followed by a paragraph</p> 
  followed by more inline text.
</div>
// demo2
<p>
  Some inline text 
  <span>followed by a paragraph</span> 
  followed by more inline text.
</p>

如上忽匈,demo1將創(chuàng)建兩個匿名塊盒房午,一個包含 p前面的文本 (Some inline text), 一個包含 p 后面的文本(followed by more inline text)丹允。

demo2將生成一個行內格式上下文郭厌,生成一個匿名行盒(line box),里面包含兩個匿名行內盒(inline box)雕蔽,Some inline textfollowed by more inline text.和一個span行內盒折柠。

OK,至于怎么觸發(fā)塊級格式上下文請看塊格式化上下文批狐。這里只為了說明IFC而介紹下BFC扇售。

當元素的 CSS 屬性 display 的計算值為 inline, inline-blockinline-table時,稱它為行內級元素嚣艇。

行內級元素生成行內級盒(inline-level boxes)承冰,參與行內格式化上下文(inline formatting context)。同時參與生成行內格式化上下文的行內級盒稱為行內盒(Inline boxes)食零。

規(guī)范里IFC文字很多困乒,提煉下我們需要的:

如果一個矩形區(qū)域,包含著一些排成一條線的盒子贰谣,稱為line box娜搂。

一個line box的寬度迁霎,由他的包含塊(containg block)和floats的存在情況決定。line box的高度百宇,由你給出的代碼決定欧引。(line-height),即所有inline box的最大高度差恳谎。

當盒子的高度小于父級盒子高度時,垂直方向的對齊'vertical-align'屬性決定憋肖。

Vertical-align(2)

在上面的vertical-align(1)中主要了解了什么是baseline因痛,以及它是如何確定的。我們繼續(xù)研究這個屬性岸更,看下面說明表格:

描述
baseline 默認鸵膏。元素放置在父元素的基線上。
top 把元素的頂端與行中最高元素的頂端對齊
text-top 把元素的頂端與父元素字體的頂端對齊
middle 把此元素放置在父元素的中部怎炊。
bottom 把元素的頂端與行中最低的元素的頂端對齊谭企。
text-bottom 把元素的底端與父元素字體的底端對齊。

除了baseline我們已經很了解之外评肆,其它幾個屬性我們貌似也能看懂债查,唯一的問題可能是父元素的頂端低端都是什么鬼???需要確定一下瓜挽,好的再次拿我們第一個例子來講解盹廷,但我們需要變一下,加點東西進去:

<div class="demo">
  <span class='line-box'>
    ![](http://upload-images.jianshu.io/upload_images/1394123-beaa89c3197bcd45?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)<span>Xx</span>
  </span>
</div>
.demo {
  background: red;
}
.line-box {
  background: blue;
  line-height: 200px;
}
.line-box img {
  vertical-align: text-bottom;
  width: 50px;
}
.line-box span {
  margin-left: 20px;
  color: yellow;
}

實例

<script async src="https://jsfiddle.net/Damonare/ck07neus/embed/html,css,result/"></script>

通過IFC部分我們知道久橙,之前的例子實際上有生成一個匿名行盒(line box)俄占,雖然他可以繼承父元素的屬性,但我們沒法直觀的去操作它??淆衷,OK缸榄,把這個匿名行盒變成可控的span元素就好了??,如上demo所示祝拯。

我們通過設置line box的line-height來控制line-box的高度,然后設置img的vertical-align屬性值甚带,來觀察具體的對齊方式。OK鹿驼,讀者你可以自行本地測試或是直接更改fiddle內容來看效果欲低。但這里很容易有個誤區(qū),就是父元素的middle畜晰,top這些值是怎么確定的砾莱?如上,我們通過更改img元素的vertical-align的值凄鼻,來觀察區(qū)別腊瑟,表面上看著好像是父元素根據Xx內容來進行確定的聚假,實則不然。我們再來看一個例子:

下面沒內容戳這

<script async src="http://jsfiddle.net/Damonare/gkqq3dvp/embed/html,css,result/"></script>

上面例子中闰非,我們更改了Xx的對齊方式膘格,發(fā)現了很奇特的現象??,當Xx設置為text-bottom或是text-top的時候父元素(ling box)被撐大了??财松,但這另一方面這也證明了瘪贱,父元素的基線和中線等并不是由文本Xx決定的,誰決定的呢辆毡?前面提過的那個空白節(jié)點決定的菜秦!??這個空白節(jié)點實際上是理解內聯元素布局的重點!不知道它的存在舶掖,很多問題是搞不清楚的球昨。那么這個空白節(jié)點又到底是怎么影響布局的呢?前面說過基線的決定著是小寫字母x眨攘,這個時候問題就來了主慰,可能你早就想問了,不同字體下面的小寫字母x底部邊緣肯定是有區(qū)別的啊鲫售,好共螺,我們在研究下font-family

Font-family

我們再來看一個??:

下面沒示例內容請戳這

<script async src="http://jsfiddle.net/Damonare/kyse4v44/embed/html,css,result/"></script>

關于字體具體的知識可以看這篇博文龟虎,我簡單的總結一下重點璃谨。首先字體是有一個字體度量的概念的,

  • 一款字體會定義一個 em-square鲤妥,它是用來盛放字符的金屬容器佳吞。這個 em-square 一般被設定為寬高均為 1000 相對單位,不過也可以是 1024棉安、2048 相對單位底扳。
  • 字體度量都是基于這個相對單位設置的,包括 ascender贡耽、descender衷模、capital height、x-height 等蒲赂。注意這里面的值是可以超出em-square范圍的阱冶。
  • 在瀏覽器中,上面的 1000 相對單位會按照你需要的 font-size 縮放滥嘴。

看上面的例子我們也能看出來木蹬,實際上一個內聯元素是有兩個高度的content-area高度(background-color實際渲染的那個高度)和 virtual-area 高度(實際區(qū)域占空間的高度也就是line-height)。??

結論

  • 所有的內聯元素都有兩個高度
    • 基于字體度量的 content-area
    • virtual-area(也就是 line-height )
  • 內聯元素都有一個空白節(jié)點存在著來確定基線等概念若皱;
  • 基線的確定和字體有關镊叁,和內部的內聯元素無關尘颓;
  • IFC很難懂;
  • line-box(行盒) 的高度的受其子元素的 line-height 和 vertical-align 的影響晦譬;
  • 我們貌似沒法用CSS來更改字體度量疤苹。

題目確實有些標題黨的嫌疑了,實際上也沒有挖很深敛腌,比如vertical-align在inline-table元素的作用效果以及sup,sub等其他的屬性值卧土,以及l(fā)ine-height具體的屬性值如何生效的都沒有涉及。我想把這篇文章重點放在布局上像樊,而且篇幅也有限夸溶。沒涉及的請自行查閱資料吧,在此說聲抱歉凶硅。??

??以上。

后記

? 從剛開始做前端扫皱,身邊CSS簡單易學但很坑的聲音就不絕于耳足绅,很多人也說HTML、CSS一星期就能學會韩脑,現在漸漸覺得真是謬論氢妈。是,單純掌握浮動段多,定位首量,對齊,居中等基礎能解決一大半的布局問題进苍,甚至百分之百加缘,因為很多情況真的是變個寫法莫名其妙就實現了想要的結果【醢。可能這也是很多人說CSS坑的原因拣宏,但實際上很多開發(fā)者是不看CSS標準的,模仿個網站或是看著視頻寫個demo就覺得掌握了CSS杠人,遠遠不是這樣的勋乾。漸漸覺得深挖CSS要比深挖JavaScript難的多...你覺得CSS坑?誰讓你不看標準呢....???♀?

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末嗡善,一起剝皮案震驚了整個濱河市辑莫,隨后出現的幾起案子,更是在濱河造成了極大的恐慌罩引,老刑警劉巖各吨,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異蜒程,居然都是意外死亡绅你,警方通過查閱死者的電腦和手機伺帘,發(fā)現死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來忌锯,“玉大人伪嫁,你說我怎么就攤上這事∨伎澹” “怎么了张咳?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長似舵。 經常有香客問我脚猾,道長,這世上最難降的妖魔是什么砚哗? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任龙助,我火速辦了婚禮,結果婚禮上蛛芥,老公的妹妹穿的比我還像新娘提鸟。我一直安慰自己,他們只是感情好仅淑,可當我...
    茶點故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布称勋。 她就那樣靜靜地躺著,像睡著了一般涯竟。 火紅的嫁衣襯著肌膚如雪赡鲜。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天庐船,我揣著相機與錄音银酬,去河邊找鬼。 笑死筐钟,一個胖子當著我的面吹牛捡硅,可吹牛的內容都是我干的。 我是一名探鬼主播盗棵,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼壮韭,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了纹因?” 一聲冷哼從身側響起喷屋,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎瞭恰,沒想到半個月后屯曹,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年恶耽,在試婚紗的時候發(fā)現自己被綠了密任。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡偷俭,死狀恐怖浪讳,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情涌萤,我是刑警寧澤淹遵,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站负溪,受9級特大地震影響透揣,放射性物質發(fā)生泄漏。R本人自食惡果不足惜川抡,卻給世界環(huán)境...
    茶點故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一辐真、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧崖堤,春花似錦拆祈、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽咙咽。三九已至老玛,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間钧敞,已是汗流浹背蜡豹。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留溉苛,地道東北人镜廉。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像愚战,于是被迫代替她去往敵國和親娇唯。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,044評論 2 355

推薦閱讀更多精彩內容

  • 問答題47 /72 常見瀏覽器兼容性問題與解決方案寂玲? 參考答案 (1)瀏覽器兼容問題一:不同瀏覽器的標簽默認的外補...
    _Yfling閱讀 13,754評論 1 92
  • 有些東西我們經常用塔插,但是我們卻并不了解它的原理,所以一旦換了場景拓哟,好多東西就不知道該怎么用了想许。最近一直很糾結ver...
    朱小維閱讀 4,938評論 8 34
  • 參考文章:深入了解CSS的line-height屬性Vertical-Align: 你需要知道的所有事【譯】Ver...
    若邪Y閱讀 3,440評論 1 6
  • 以下文章是我在網上收集的內容,為了記錄自己的學習以及為了以后不到處找而記錄下來,如果對你有用流纹,請感謝寫這些文章的前...
    DCbryant閱讀 940評論 0 2
  • 這么多天不更新是因為要結婚忙的事情太多 一向淡定的林大頭知道今天要坐車回去結婚后也變得不淡定了糜烹,昨晚一直處于亢奮狀...
    林大頭家的小兔子閱讀 681評論 0 2