深刻理解行內元素的佈局

前言

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

白茶清歡無別事,我在等風,也在等你。😊瀏覽器

正文

講道理line-height和vertical-align 這對基是十分低調的,平常開發中碰到的不少莫名其妙的bug很大一部分都是這倆貨搞出來了的,但不多有人知道這對基的罪惡,由於可能花式改寫一下CSS代碼問題就解決了。實際上搞明白這倆東西才能讓咱們在佈局工做中游刃有餘。本文接下來就經過這對基的關係來了解內聯元素具體的佈局問題~we are刨根問底攔不住~😝markdown

​ 讀這篇文章以前請肯定您有如下知識基礎:less

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

引出vertical-align

首先來看一個🌰:ide

<div class="test">
  <img src="https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2017/10/30/d939d49ba6d9be043bb7ca8cecb6f05a~tplv-t2oaga2asx-image.image" alt=""><span>Xx</span>
</div>複製代碼
.test {
      background: red;
}
img {
    width: 50px;
    height: 50px;
}
span {
    background: white;
}複製代碼

下面無實例內容的話戳這裏oop


Xx

​ 如上代碼片斷result所示,圖片下面有一明顯的紅色條條,😡什麼鬼,很詭異不是麼,我要的是img充滿整個div啊!!!好吧,我加了一個額外的inline元素填寫內容Xx,發現原來多出來的那一塊正好是文字的下半空白部分。吆喝,這麼巧?實際上,若是將這裏的Xx內容去掉,只剩下img,那個條條依然存在,表現行爲好像父元素div裏面除了img元素還有一個空白的元素同樣,😕姑且叫它空白節點吧(肉眼中不存在卻在影響着佈局),這個是比較詭異的一個表現,查標準沒找到有相關的說明。但請將這個空白節點先記住,咱們的重點是研究條條是咋出來的。這條條看上去貌似是文本和圖片垂直方向上對齊生成的,那麼這就引粗來一個問題,inline元素默認的垂直方向的對齊方式是什麼樣的?也就是vertical-align的默認值是啥?佈局

​ OK,🤣I know you know。vertical-align默認值是baseline,OK,那就先來挖一挖vertical-align具體是個什麼鬼。測試

Vertical-align(1)

vertical-align這個屬性我感受是CSS中最複雜的屬性之一了...好多問題概念也讓人看不懂...一方面它是做用在inline元素和table-cell元素身上,屬性值特別多,另外一方面該屬性規範裏並無一個定論,致使一些屬性不一樣瀏覽器的實現也不一樣,因此兼容性問題不少。對於一些 可替換元素,好比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元素自己是有高度的,二者基線對齊天然就如上面那樣表現了。🐷

😳好吧,等會,到這裏,咱們發現實際又多了倆概念——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>複製代碼

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

如上可證實,inline元素的高度決定者是line-height,並非文字內容撐開的。✌️

CSS規範裏對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要複雜得多,規範裏IFC的篇幅也要比BFC多得多。

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

但塊容器盒要麼只包含行內盒,要麼只包含塊級盒。但一般會同時包含二者。在這種狀況下,將建立匿名塊盒來包含毗鄰的行內級盒。

看個🍐:

//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將建立兩個匿名塊盒,一個包含 p前面的文本 (Some inline text), 一個包含 p 後面的文本(followed by more inline text)。

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

OK,至於怎麼觸發塊級格式上下文請看塊格式化上下文。這裏只爲了說明IFC而介紹下BFC。

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

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

規範裏IFC文字不少,提煉下咱們須要的:

若是一個矩形區域,包含着一些排成一條線的盒子,稱爲line box。

一個line box的寬度,由他的包含塊(containg block)和floats的存在狀況決定。line box的高度,由你給出的代碼決定。(line-height),即全部inline box的最大高度差。

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

Vertical-align(2)

在上面的vertical-align(1)中主要了解了什麼是baseline,以及它是如何肯定的。咱們繼續研究這個屬性,看下面說明表格:

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

除了baseline咱們已經很瞭解以外,其它幾個屬性咱們貌似也能看懂,惟一的問題多是父元素的頂端低端都是什麼鬼?😳須要肯定一下,好的再次拿咱們第一個例子來說解,但咱們須要變一下,加點東西進去:

<div class="demo">
  <span class='line-box'>
    <img src="https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2017/10/30/d939d49ba6d9be043bb7ca8cecb6f05a~tplv-t2oaga2asx-image.image" alt=""><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;
}複製代碼

實例

經過IFC部分咱們知道,以前的例子實際上有生成一個匿名行盒(line box),雖然他能夠繼承父元素的屬性,但咱們無法直觀的去操做它😤,OK,把這個匿名行盒變成可控的span元素就行了🤣,如上demo所示。

咱們經過設置line box的line-height來控制line-box的高度,而後設置img的vertical-align屬性值,來觀察具體的對齊方式。OK,讀者你能夠自行本地測試或是直接更改fiddle內容來看效果。但這裏很容易有個誤區,就是父元素的middle,top這些值是怎麼肯定的?如上,咱們經過更改img元素的vertical-align的值,來觀察區別,表面上看着好像是父元素根據Xx內容來進行肯定的,實則否則。咱們再來看一個例子:

下面沒內容戳這

上面例子中,咱們更改了Xx的對齊方式,發現了很奇特的現象🙄,當Xx設置爲text-bottom或是text-top的時候父元素(ling box)被撐大了🌺,但這另外一方面這也證實了,父元素的基線和中線等並非由文本Xx決定的,誰決定的呢?前面提過的那個空白節點決定的!🐂這個空白節點其實是理解內聯元素佈局的重點!不知道它的存在,不少問題是搞不清楚的。那麼這個空白節點又究竟是怎麼影響佈局的呢?前面說過基線的決定着是小寫字母x,這個時候問題就來了,可能你早就想問了,不一樣字體下面的小寫字母x底部邊緣確定是有區別的啊,好,咱們在研究下font-family

Font-family

咱們再來看一個🌰:

下面沒示例內容請戳這

關於字體具體的知識能夠看這篇博文,我簡單的總結一下重點。首先字體是有一個字體度量的概念的,

  • 一款字體會定義一個 em-square,它是用來盛放字符的金屬容器。這個 em-square 通常被設定爲寬高均爲 1000 相對單位,不過也能夠是 102四、2048 相對單位。
  • 字體度量都是基於這個相對單位設置的,包括 ascender、descender、capital height、x-height 等。注意這裏面的值是能夠超出em-square範圍的。
  • 在瀏覽器中,上面的 1000 相對單位會按照你須要的 font-size 縮放。

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

結論

  • 全部的內聯元素都有兩個高度
    • 基於字體度量的 content-area
    • virtual-area(也就是 line-height )
  • 內聯元素都有一個空白節點存在着來肯定基線等概念;
  • 基線的肯定和字體有關,和內部的內聯元素無關;
  • IFC很難懂;
  • line-box(行盒) 的高度的受其子元素的 line-height 和 vertical-align 的影響;
  • 咱們貌似無法用CSS來更改字體度量。

題目確實有些標題黨的嫌疑了,實際上也沒有挖很深,好比vertical-align在inline-table元素的做用效果以及sup,sub等其餘的屬性值,以及line-height具體的屬性值如何生效的都沒有涉及。我想把這篇文章重點放在佈局上,並且篇幅也有限。沒涉及的請自行查閱資料吧,在此說聲抱歉。😞

❤️以上。

後記

​ 從剛開始作前端,身邊CSS簡單易學但很坑的聲音就不絕於耳,不少人也說HTML、CSS一星期就能學會,如今漸漸以爲真是謬論。是,單純掌握浮動,定位,對齊,居中等基礎能解決一大半的佈局問題,甚至百分之百,由於不少狀況真的是變個寫法莫名其妙就實現了想要的結果。可能這也是不少人說CSS坑的緣由,但實際上不少開發者是不看CSS標準的,模仿個網站或是看着視頻寫個demo就以爲掌握了CSS,遠遠不是這樣的。漸漸以爲深挖CSS要比深挖JavaScript難的多...你以爲CSS坑?誰讓你不看標準呢....🤷‍♀️

相關文章
相關標籤/搜索