前段時間組內同窗在開發運營頁的過程當中,遇到一個有趣的問題:移動端頁面採用 rem自適應佈局
,圖片在垂直方向展現時會出現莫名的間隙(以下圖所示)。幾位同窗紛紛提出不一樣的解決方案,但爲何會出現這種問題呢?秉着知其然且知其因此然,藉此行文一篇,大體梳理行內元素視覺格式化方面理論。css
上面的問題其實三言兩語就能夠說個大概,不過擴散到相關知識點卻不能簡單的一語帶過。看過《CSS權威指南》的童鞋會知道,書中第七章有專門講視覺格式化方面理論。同時 CSS
規範在第9、十章也分別有闡述用戶代理如何處理視覺格式化。相比塊級元素,行內元素的視覺顯示基本術語多也難理解。html
塊級元素生成塊級框,一般不容許其餘內容與這些框並存。在充分理解盒模型( BoxModel
)後,水平和垂直方向格式化表現很容易預測。行內塊級元素能夠說是行內元素和塊級元素的混合物,實際上行內塊級元素表現與行內替換元素類似。bash
行內元素的視覺顯示則涉及較多術語,例如行內替換元素、行內非替換元素、內容區、行內框、行框、字體大小、基線、 lin-height
、 vertical-align
等,同時也會產生不少意思的問題。wordpress
注:後文討論主要爲常規流(
normal flow
)中的行內元素(inlineelements
)佈局,不包括浮動(float
)、定位(position
)元素。後文描述box
爲「框」,也可爲「盒」,相贊成思不一樣翻譯。佈局
常規流( normal flow
):文檔文本按照從左向右、從上向下順序顯示(自右而左語言相反)。脫離常規流能夠採用浮動或定位方式。測試
非替換元素( non-replaced elements
):若是元素內容包含在文檔中,則稱爲非替換元素。例如包含文字的段落。字體
替換元素( replaced elements
):指用做爲其餘內容佔位符的一個元素。 img
元素就是其中經典例子。flex
塊級元素( block-level elements
):塊級元素會在其框以前和以後生成"換行",處在正常流中的塊級元素會垂直襬放。spa
行內元素( inline-level elements
):行內元素不會獨佔一行,相鄰的行內元素會排列在同一行中。.net
包含塊( containing block
):CSS規範中制定一系列規則來肯定元素的包含塊。對於正常流中元素,包含塊由最近塊級祖先框的內容邊界( content edge
)構成。詳情見CSS規範10.1章節 Definitionof"containing block"
,注意與塊容器區分( block container
)。
注:上述部份內容引自《CSS權威指南 第三版》第七章
在進一步介紹行內格式化以前,先來回顧一些行內佈局的基本術語。(略枯燥,不過明白概念才能更好理解視覺效果)
匿名文本( anonymous text
):指全部未包含在行內元素的字符串。 CSS
規範中對匿名文本所處上下文分別有匿名塊級框( anonymous block boxes
)和匿名行內框( anonymousinlineboxes
)生成規則。(詳情見CSS規範:9.2.1.一、9.2.2.1章節)
匿名行內框( anonymousinlineboxes
):任何被直接包含在一個塊容器元素中(不在行內元素裏面)的文本,必須視爲一個匿名行內元素,生成匿名行內框。
內容區( content area
):在非替換元素中,內容區能夠是元素中各字符的em框串在一塊兒構成的框,也能夠是由元素中字符字形描述的框。替換元素中,內容區是元素固有寬高加上可有的外邊距、邊框或內邊距。注意非替換元素內容區的高度應該基於字體, CSS
規範對此沒有做具體說明。
行間距( leading
):行間距爲 line-height
和 font-size
值之差。差值分爲兩半(半間距 half-leading
)分別應用到內容區的頂部和底部。注意行間距只應用於非替換元素,能夠爲負值。
行內框( inlineboxes
):行內框是經過向內容區增長行間距來描述。對於非替換元素,元素行內框的高度恰好等於 line-height
值。對於替換元素,元素行內框的高度等於內容區高度。
行框( line boxes
):包含同一行中出現的行內框的最高點和最低點的最小框。換句話說,行框的上邊界要位於最高行內框的上邊界,而行框的底邊要放在最低行內框的下邊界。
注:上述部份內容引自《CSS權威指南 (第3版)》第七章
以上術語在初次閱讀狀況下,看起來仍是比較費解,建議參照《CSS權威指南(第3版)》第七章理解。以下圖所示:假如行內非替換元素的 font-size
爲15px, line-height
爲21px,則行間距爲6px。相同行只存在惟一行內框,因此行框高度和行內框相同都爲21px。
對於行框和行內框關係,能夠簡述爲:行內框是由行內元素產生,行框則是一行中全部的行內框構成。
在繼續介紹以前,有必要了解行內如何逐步構造一個行框,而且經過格式化過程清楚如何肯定各部分高度。
按照如下步驟肯定行中各元素行內框以及高度:
獲取各行內非替換元素及不屬於後代內元素的全部文本的 font-size
值和 line-height
值, line-height
和 font-size
差值爲行間距值。
獲取替換元素高度及上、下外邊距,上、下內邊距,上、下邊框值相加。
對於內容區,須要肯定各元素、匿名文本以及該行自己基線的位置,將其基線對齊。對於替換元素,須要底邊放置該行基線上。
對於指定 vertical-align
值的元素,肯定其垂直偏移量。並改變元素在上方或下方超出的距離。
肯定各行內框的具體位置後再進行肯定行框。行框高度爲最高行內框頂端和最低行內框低端之間的距離。
其餘要點
行內元素的背景應用於內容區及全部內邊距。
行內元素的邊框要包圍內容區及全部內邊距和邊框。
垂直方向替換元素和非替換元素的視覺表現不盡相同。非替換元素的內、外邊距和邊框對其生成的框沒有垂直效果,它們不會影響元素行內框的高度,以及該元素所在行框的高度。
替換元素的外邊距和邊框會影響行內框高度,也可能影響行框的高度。
上述流程已經對於行內元素格式化作一個大概介紹。但其中還有些細節問題,如何肯定行框的基線位置,行內替換元素爲何會出現空隙(文章首部圖所示), line-height
如何影響行高, vertical-align
與 line-height
又有何關係, vertical-align
又是如何影響視覺格式化等等。
在行內相關模型中,凡是涉及到垂直方向的排版或對齊,都離不開最基本的基線( baseline
)。那基線又是如何肯定的呢?
匿名文本x的下邊緣(線)
這裏指不包含在行內元素中的匿名行內框裏面的字符 x
的底部。具體測試方法可在包含塊中添加匿名文本 x
查看與該行圖片底部位置,以下圖所示。
演示請點擊 codepen.io/sunpeijun/p…
回到開篇所提到的問題,如上圖所示,兩張圖片間爲何會出現莫名間隙?前面鋪墊那麼多,也是爲了這塊說道時更方便。首先這裏有個前提,圖片元素爲行內替換元素,html採用 rem
佈局,設置根元素 font-size
爲100px,圖片元素 font-size
繼承根元素節點值100px。代碼結構以下:
<div> <img src='./images/bg1.jpg'> <img src='./images/bg2.jpg'></div>複製代碼
演示請點擊 codepen.io/sunpeijun/p…
很明顯的是每張圖分別處於一個行框中。對於 line-height
默認值 CSS
規範中建議用戶代理設置介於1.0到1.2。同時 line-height
值是相對於元素自己的 font-size
值計算,則這裏圖片元素 line-height
爲100px(假設用戶代理設置 line-height
默認爲1)。圖片做爲行內替換元素,其在行內默認會與行框基線對齊。這裏用戶代理會產生空的匿名文本行內框,框的高度則等於 line-height
值。
因爲高度值較小圖片元素生成的行內框高度小於匿名文本行內框值(100px),行框高度爲同一行中出現的行內框的最高點和最低點的最小框,很容易看出這裏行高爲100px。圖片高度小於行高,視覺上會出現圖片周圍存在空白,就是上圖中所示莫名空隙。其實主要緣由仍是 line-height
值過大撐起行框致使。
那麼如何解決這個問題呢?
設置圖片包含塊( containing block
) line-height:0
,此時空匿名文本 line-height
繼承包含塊值,行內框值爲0。那麼行框邊界則爲圖片元素生成的行內框最高點和最低點,行框高度等於圖片原有高度。
設置圖片包含塊( containing block
) font-size:0
,空匿名文本框繼承 font-size
值, line-height
計算值也爲0,原理同上。
設置圖片元素 display:block
。這麼作目的是阻止產生行內格式化模型,所以也不存在 lin-height
計算值、行框、行間距屬性。
設置圖片包含塊樣式屬性爲 display:flex;flex-direction:column;
,本質上也是阻止產生行內格式化上下文。
演示請點擊 codepen.io/sunpeijun/p…
附: CSS
規範中對空匿名文本行內框描述(詳情見 CSS
規範 10.8.1章節)
each line box starts with a zero-width inline box with the element's font and line height properties.
這裏也能夠換種表述方式, line-height
屬性和行框的高度有何關係。查閱 CSS
規範, line-height
描述以下:
On a block container element whose content is composed of inline-level elements, 'line-height' specifies the minimal height of line boxes within the element. 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.
筆者不才,嘗試翻譯。對於一個內容由行內級元素組成的塊容器元素, line-height
指定元素內行框的最小高度。這個最小高度包含基線上方的最小高度和下方的最小深度。就像每一個行框以一個具備該元素字體和行高屬性的寬度爲0的行內框開始。(筆者注:也就是上文提到空匿名文本行內框)
注意規範中有明確表示, line-height
指定元素內行框的最小高度。由此看來 line-height
值並非絕對等於行框的高度。那如何去理解最小高度呢?其實這個問題的範疇已經在上文隱式說起過。
首先行框中包含替換元素和非替換元素,對於非替換元素,元素行內框的高度則等於 line-height
值。對於替換元素, line-height
屬性無效,元素行內框的高度等於內容區高度(見上文基礎術語行內框定義)。參照上文 視覺格式化流程
章節,假如行框內存在替換元素( img
)的行內框高度大於非替換元素行內框高度( line-height
值),又因行框的高度爲行內框的最高點到最低點距離,因此此時行框的高度要大於 line-height
值。
那什麼狀況下,行高等於 line-height
值,也就是前面所說的最小高度呢?顯而易見,行框中只存在非替換元素或存在替換元素,但替換元素行內框要小於 line-height
值。(多個行內框的狀況下需具備相同 line-height
值)
談及 line-height
和 vertical-align
關係,張鑫旭老師有篇博文描述爲基友。爲什麼基友呢,拋個問題: line-height
值爲百分比時如何計算, vertical-align
值爲百分比時又是相對於誰呢?其實前者相對於元素 font-size
計算,後者相對於元素 line-height
值計算。
心生疑惑, vertical-align
百分比值爲什麼要相對於 line-height
值計算?通常咱們認爲元素在垂直方向相關屬性百分比值,可能是根據元素包含塊的高度或自己高度計算,好比 height、top、translateY
等。不過對於行內非替換元素垂直方向 height、margin、padding
屬性是不生效的,那麼退而求其次能肯定的也就是 line-height
值了。基友關係也就油然而生,我的理解非權威。
再來看一個栗子,和 行內替換元素間爲何會出現空隙
章節文檔結構一致,兩張圖片包含在塊級元素中,但並未設置 html
元素 font-size:100px;
屬性。爲減小圖示方便說道,添加匿名文本 x
做爲輔助,以下圖所示。
演示請點擊 codepen.io/sunpeijun/p…
首先這裏並無設置html元素 font-size:100px
,行內框的高度也不會出現過大(等於100px)現象,那爲何還會出現空白間隙呢?
由於空匿名文本行內框。
行內替換元素垂直方向默認採用 baseline
對齊,替換元素底部放置在行框基線上。此時行內會產生空匿名文本框肯定行框基線位置(以上圖字符 x
行內框爲例)。但文本行內框的底部在基線下面,且行框的底端應包含文本框底端。也就是說行框包含了基線位置下面空白。圖示間隙實際上是文本框基線如下至文本框底部的區域。
知其緣由後,解決起來也就瓜熟蒂落。除上文 行內替換元素間爲何會出現空隙
章節說起的方法可用外,這裏咱們還可使用 vertical-align
屬性來解決。圖片元素設置:
img { vertical-align: top;}複製代碼
演示請點擊 codepen.io/sunpeijun/p…
爲何? vertical-align:top
屬性使圖片元素垂直方向與行框頂部對齊,天然文本框底部也再也不是行框的底部,圖片生成行內框的高度也就成爲行框的高度(限於 line-height
值小於圖片高度情形)。
參閱規範, vertical-align
屬性會影響由一個行內級元素生成行內框在行框內部的豎直定位。由此可知, vertical-align
在不一樣屬性值狀況下,對行框的佈局和高度會產生相應影響。
vertical-align
還有個耐人琢磨的屬性值: middle
, CSS
規範定義其爲:
Align the vertical midpoint of the box with the baseline of the parent box plus half the x-height of the parent.
簡譯之,把該框的垂直中點和父級框的基線加上父級的半 x-height
對齊。 x-height
又是什麼意思,其實這裏是指小寫字符 x
的高度。術語描述就是基線和等分線( mean line
)(也稱做中線( midline
))之間的距離。維基百科中圖示以下:
vertical-align:middle
其實並不會絕對垂直居中,咱們日常看到的 middle
只是一種近似的效果。緣由很簡單,由於不一樣的字體,其在行內盒子中的位置是不同的。
比方說「微軟雅黑」就是一個字符下沉比較明顯的字體,全部字符的位置相比其餘字體要偏下一點。你會發現圖標和文字不在一條線上,而是相對於字符 x
的中心位置對齊,咱們肉眼看上去就好像和文字居中對齊了。
順便延伸下, height=line-height
處理方式對於單行文原本說是絕對的垂直居中嗎?
注:上述部份內容引自張鑫旭老師博文《字母’x’在CSS世界中的角色和故事》。
儘管 CSS
格式化模型的某些方面乍看起來有些不太直觀,不過多熟悉一些就會發現這其中是有道理的。相對於塊級元素,行內元素在視覺格式化方面更爲晦澀難懂。同時行內元素還要考慮替換元素和非替換元素情形,替換元素的加入也使得視覺格式化方面略顯複雜。
此外行內元素涉及到的概念或術語可能是不可見的,好比匿名框( anonymous boxes
)、行內框( inlineboxes
),行框( line boxes
),但實際卻起着重要做用。同時又有 font-size、line-height、vertical-align
屬性左右着行內佈局。只知其一;不知其二或淺嘗輒止終不能深刻,靜下來慢慢閱讀會收穫頗豐。
本篇文章就書寫至此,若是想對格式化方面理解更深,還請多讀《CSS權威指南》多讀 CSS
規範。書中自有千鍾粟。
初寫技術文章,多擔心某處誤導讀者。下筆很多天,仍會有不嚴謹之處。若有疑問或錯誤,敬請斧正,先行謝過。
參考文獻
《CSS權威指南(第3版)》
打個廣告,歡迎關注筆者的公衆號