在寫做本文章前本來打算只是複習一下 line-height
和 vertical-height
這兩個屬性而已, 結果發現掉進了一個大坑網上有不少篇文章看的我雲裏霧裏的, 最後決定仍是從頭來一遍吧, 這篇文章是此次的一個記錄.css
此次的故事雖然時由於 line-height
和 vertical-align
這兩個屬性引發的, 可是實際上本篇文章中主要探討的話題是 "文本是如何渲染", 雖然這兩個屬性與話題關聯很大可是本文中不會過多的說起它們, 請確保熟悉它們.html
你也能夠直接跳過這章, 去閱讀後面精彩的部分, 若是遇到了概念問題能夠在回來進行查閱.ios
咱們這裏不會仔細的討論 "內聯元素", 只是爲了後面的內容作鋪墊, 這些內容可能須要你提早預習.瀏覽器
另外 "內聯元素" 和 "行內元素" 其實是同一個東西只是叫法不一樣, 可是本篇文章中沒有統一叫法.ide
一個內聯元素只佔據它對應標籤的邊框所包含的空間。svg
默認狀況下,行內元素不會以新行開始,而塊級元素會新起一行。工具
常見的內聯元素有:佈局
在 CSS 中, 可替換元素( replaced element)的展示效果不是由 CSS 來控制的。這些元素是一種外部對象,它們外觀的渲染,是獨立於 CSS 的。
典型的替換元素有:post
<iframe>
<video>
<embed>
<img>
那些沒有 "特異功能" 的 "內聯元素" 就是 "非替換元素", 典型值以下:測試
<span>
<em>
<strong>
<i>
內聯元素除了 "行內元素不會以新行開始" 這種你們都知道的特性外, 還有幾點特殊的表現. 例如塊級元素上的幾個常見屬性:
這些屬性對於內聯元素來講不會影響其垂直高度, 可是這不意味着這些內容被裁剪掉了而是由於 margin
是透明的而 padding
一般來講也是透明的.
惟一例外的是 border
它能夠被看到, 不過依然不會影響垂直高度:
圖片中文字 "Emmm" 被 <em>
包裹了起來而且設置了 margin
和 padding
和 border
請仔細觀察在 "垂直方向" 實際上高度並無增長.
注意:這種表現只會出如今 "非替換元素" 上, "替換元素" 的表現是不一樣的後文中會提到.
咱們先從字體開始, 由於文本佈局的基本單位毫無疑問是由文字組成的:
<div>hello world</div>
當討論的文字的時候, 最多見的有關 css 屬性就是 font-size
了, 一般認爲 font-size
指定的值就是文字的大小.
想要證實 font-size
不等於 "字體大小" 實際上很是簡單, 打開瀏覽器的開發者工具你就能夠證實這點, 例如咱們有以下的代碼:
<body> <div style="font-size:25px">hello world</div> </body>
慣性思惟會讓咱們認爲這個元素的大小就是 25px
.
哈哈!歡迎來到css世界:
上圖中咱們看到一個 font-size:25px
的元素卻佔據了 32.8px 的高度的空間.
實際上, font-size 屬性與你看到的實際字體大小之間的具體關係由字體的設計者來肯定. 這種關係設置爲字體自己中的一個 em 方框(有人也稱爲 em 框).css權威指南(第三版)
你設置的 font-size
實際上控制的是文字的 em框
而不是字體的自己的大小, 而 em框
與文本之間的間距是由字體的設計者決定的.
em框
的概念就相似小學使用的田字格, 全部字體都相對於田字格進行書寫.
不過按照上面的理解, font-size
控制的是 em框
的大小, 按照這樣的設計字體大小至少不會超過 "25px" 纔對.
沒錯實際上大部的字體都嚴格遵照了 em框
的大小限制, 當咱們將 line-height
大小設置爲 font-size
同樣的時候:
<div style="font-size:25px;line-height:25px">hello world</div>
咱們發現字體渲染大小都是小於或者等於 "25px" 的:
那麼多出去的高度是從哪裏來的?
實際上字體做者有至關大的權力來控制字體,不只可讓字體大小超過 em框
, 還能夠指定字體的上下留白空間.
具體能夠參考這篇文章, 從製做字體的角度解釋了字體的渲染表現, 從而能夠解釋 "不一樣字體之間爲何差別這麼大" 這個使人頭大的問題.
在MDN上對於 line-height
有以下大體的描述:
當 line-height 使用默認值的時候(這個值是 normal), 這個值約爲 1.2(不一樣瀏覽器不一樣), 取決於元素的
font-family
.
注意💥:如下的內容是我不嚴謹的猜想, 請不要盲目相信.
不過根據個人測試, 字體設計上提供的超出 em框
的留白是會被 line-height
覆蓋的.
固定 font-size:20px
且無 line-height
狀況下 "微軟雅黑" 字體行框高度爲 26.4px, 一旦手動添加 line-height:1.2
後行框高度變爲 24px.
例子地址:
https://jsbin.com/dicaqocize/...
"baseline" 被稱爲 "基線", 也是由字體做者定義的, 不過常見的文字基線是該字體的英文字母小寫 "x" 的底邊緣, 若是說 em框
是田字格, 那麼 baseline
就是英語練習冊上的 "四線三格", 指定了文字對齊的位置, 有以下的例子:
<body> <div style="font-size:25px"> <span style="font-family:Ubuntu Mono">xYz你好</span> <span style="font-family:微軟雅黑">xYz你好</span> <span style="font-family:宋體">xYz你好</span> </div> </body>
咱們指定了多種不一樣的字體, 因爲這幾種字體的基線都是 "小寫英文字母x的底邊緣", 即便他們的默認行高不一樣可是經過基線對齊後它們在視覺上造成了統一, 下面的這張圖片能夠揭示它們對齊的方式, 圖片中綠色的線表明基線可能的位置:
可是一旦選中這些文字即可以察覺它們之間的差別:
🔥🔥🔥💥💥前方大量術語警告.
行佈局實際上要比常提到的塊佈局複雜的多. 因此在瞭解行佈局前咱們須要瞭解幾噸相關的術語, 固然若是你已經瞭解過了能夠直接跳過.
<span> <a> <em> ...
等這些 display:inline
的元素.<p>hello world</p>
中的 "hello world" 沒有被 "行內元素" 包裹起來, 因此它就是 "匿名文本".css
控制的元素被稱爲 "替換元素", 例如 <img> <video> <audio> <iframe> ...
.width height...
可是你沒法操控其內部的渲染,例如: 你沒法控制 <iframe>
內部顯示頁面的具體細節.em框
組成內容區.line-height
- font-size
的差就是行間距(參考 em框
小節).
通常來講行間距能夠被平均分爲兩部分, 一部分在行前一部分在行後.
能夠理解爲 word 中的 "段前" "段後"的概念, 不過在 css
中只有 "行間距" 沒法單獨設置 "行前" 和 "行後".
line-height
大小就是 "行內框" 的高度.行框是由一行中最高的行內框和最低的行內框所撐開的.
至關很差理解對吧, 那麼爲何有這麼多概念呢? 考慮下方的圖片:
在一行文本中可能會存在各類因素影響着文本的顯示, 例如上圖中存在着多種字體的狀況. 並且這張圖片中尚未考慮同一行存在 <img>
這種替換元素的狀況.
複雜的設計其實是爲了知足複雜的須要.
爲了方便考慮, 咱們如今只討論一行或者多行中只存在 "非替換元素" 和 "匿名文本" 的狀況.
咱們知道 "font-size
肯定了內容區域的高度(由於 font-size
肯定了 em框
而多個 em框
構成內容區域).
若是一個行內元素的 font-size
是 15px, 那麼內容區域的高度就是 15px, 且 em框
的高度也是 15px:
<span style="font-size:15px">hello world</span>
假設咱們設置 line-height
爲 21px, 那麼用戶代理(瀏覽器)會經過 line-height
減去 font-size
而後在除以2, 將這兩份高度補到到 em框
的上面以及下面此時構成了 "行內框":
此時咱們在段落中填入一個超大號的 <strong>
:
<p style="font-size:25px;line-height:25px"> hello world<strong style="font-size:80px">Emmmm.</strong> </p>
這個例子中 "hello world" 這個匿名文本的 line-height
是 25px(line-height有繼承特性), 一樣的 <strong>
標籤中的內容也繼承了 line-height
也就是 25px.
根據 "行內框" 計算規則 line-height
減去 font-size
除以 2 --> (25-80)/2 = -27.5
這些負值被添加到原有的 em框
上構成 "行內框".
因此就形成了一種 "行內框" 比 "內容區域" 小的狀況, 並且更加有趣的是 "行內框" 的下邊緣實際上會向上提高, 由於大部分的文字都靠近 em框
的中下部分:
在默認狀況下文本是按照 "基線對齊" 的, 因此會形成下面的結果, 行框高度超出了 line-height
的高度:
計算完成 "行內框" 後的 <strong>
標籤的基線掉出了 "行內框", 因爲文本須要按照 "基線對齊" 因此 <strong>
和 "hello world" 文本進行基線對齊, 不過計算完成後的 <strong>
的 "行內框" 被總體上擡甚至比基線還要高, 而 "行框" 是根據整行文本中 "行內框" 的最高值和最低值決定的, "hello world" 文本佔據了最低值, 而最高值由 <strong>
標籤佔據, 因此 "行框" 的高度比 line-height
還要高.
下面的這張圖描述了這種渲染行爲:
CSS 的屬性 vertical-align 用來指定行內元素(inline)或表格單元格(table-cell)元素的垂直對齊方式。
vertical-height
是一個十分複雜的屬性, 其中有幾個屬性的做用方式是和以前討論的 "行框模型" 的關係是十分密切的, 包括如下幾個屬性:
行內框文本頂端與行框的頂端進行對齊
行內框的底部與行框的底部進行對齊
將元素行內框的頂端與父元素的內容區的頂端對齊
將元素行內框的底端與父元素的內容區的底端對齊
將元素行內框的垂直中點與父元素基線上的 0.5ex 處對齊
將元素的內容區和行內框上移. 上移動的距離由用戶代理實現.
將元素的內容區和行內框下移. 下移動的距離由用戶代理實現.
相對於行高計算後在將值應用到基線上控制上下移動的距離.
px
em
.... 等常見的 css 單位
接下來咱們來使用 "top" 這個屬性來研究一番, 咱們在以前的例子中新增一些內容:
<p style="font-size:25px;line-height:25px"> hello world <strong style="font-size:80px">Emmmm.</strong> <span style="vertical-align:top">foobar</span> </p>
你是否能夠解釋下方的渲染結果呢:
咱們新添加的 "內聯元素" <span>
繼承了父元素的 font-size:25px;line-height:25px
, 因爲 <span>
標籤設置了 vertical-align:top
因此他的 "行內框" 頂部和咱們的 "行框"(藍色區域) 頂部進行了對齊.
解析圖:
咱們再在原有的基礎上加點料:
<p style="font-size:25px;line-height:25px"> hello world <strong style="font-size:80px">Emmmm.</strong> <span style="font-size:40px;vertical-align:top;line-height:10px">foobar</span> </p>
相信你能夠解釋下方的結果了吧:
由於裝載 "foobar" 文本的 <span>
標籤, 被設置了一個較大的字體和一個極小的行高, 文本每每在 em框
靠下的位置而通過 "行內框" 生成後, 上下各自減去一樣大小的數值, 致使計算完成的 "行內框" 的底部提高, 甚至超過了文字的基線.
使用 vertical-align:top
讓 <span>
的行內框的頂部與行框進行對齊, 致使部分超出 <span>
元素的 "行內框" 的文本超出 "行框".
在以前的章節中咱們知道了 line-height
的高度實際上就是 "行內框" 的高度. 若是設置了錯誤的 line-height
的高度可能會帶來多行疊加的狀況.
當一行中含有不一樣大小字體的時候咱們該如何指定一個良好的 line-height
的呢, 例如:
<p >Lorem ipsum dolor sit amet, consectetur adipisicing elit. <strong style="font-size:50px;">big Text</strong> dolorum inventore tempora, laboriosam esse a veritatis quae nihil mollitia </p>
渲染的結果:
問題所在的緣由就是 "行內框" 的高度比 "內容區域" 小, 致使多出去的內容區域渲染的內容溢出. 解決的問題很簡單確保行內框要比內容區域大就能夠了.
咱們手動的給大號字體指定一個 line-height
其值要大於等於 font-size
:
<p >Lorem ipsum dolor sit amet, consectetur adipisicing elit. <strong style="font-size:50px;line-height:1em">big Text</strong> dolorum inventore tempora, laboriosam esse a veritatis quae nihil mollitia </p>
或者使用 line-height
的縮放因子:
<p style="line-height:1.5">Lorem ipsum dolor sit amet, consectetur adipisicing elit. <strong style="font-size:50px">big Text</strong> dolorum inventore tempora, laboriosam esse a veritatis quae nihil mollitia </p>
因爲 line-height
具備繼承的特性因此 <p>
下的全部內容都繼承了這個值, 而 "縮放因子" 是根據當前元素的 font-size
進行計算的, 因此 <strong>
會有一個相對對其字號 1.5 倍大小的 line-height
值.
不過這裏依然存在一些問題, 咱們知道 "行內元素" 能夠設置 padding
margin
和 border
, 其中 margin
和 padding
在垂直方向的值是能夠設置也存在可是不會影響到垂直方向的表現.
border
和 margin
還有 padding
的表現一致, 可是有一點不一樣的是 border
大部分狀況下都是由顏色的. 若是 border
在垂直方向的高度大於 "行間距" 的話, 這樣又會形成重疊:
所以在指定 line-height
的時候你還須要囊括 boder
的高度這樣才能避免重疊的問題:
<p style="line-height:1.5">Lorem ipsum dolor sit amet, consectetur adipisicing elit. <strong style="font-size:50px;border-top:20px solid;line-height:calc(1.5em + 20px)">big Text</strong> dolorum inventore tempora, laboriosam esse a veritatis quae nihil mollitia </p>
使用 calc
能夠進行自動計算, 固然手動指定一個高度也是能夠的.
在此以前咱們只討論了 "非替換元素" 的表現, "替換元素" 表現有些區別因此這些進行詳細介紹.
不過在此以前, 咱們再次回顧一下 "替換元素" 有哪些呢, 常見的有:
<iframe>
<video>
<embed>
<img>
以及 "創建框" 中和 "非替換元素" 稍有不一樣的兩個步驟:
對於 "替換元素" 來講, 元素的固有高度在加上可能存在的外邊距邊框或者內邊距.
當元素是替換元素的時候, 行內框的高度等同於 "替換元素" 內容區高度, 由於行間距不會應用到替換元素上.
如今開始觀察一個實際的例子而且嘗試解釋佈局的緣由:
<body> <p style="font-size:20px;line-height:1">hello <img src="http://temp.im/100x30" alt=""> world</p> </body>
圖片:渲染結果:
根據以前的 "行內框" 的描述, 由於咱們的 <img>
內容的高度是 30px, 這個高度對於 "替換元素" 來講既是 "內容區" 的高度也是 "行內框" 的高度, 因此這二者的高度都是 30px.
默認狀況下 vertical-align
的對齊方式是 "baseline"(基線) 對齊, 對於 "替換元素" 來講 "基線" 就是元素的底邊緣, 因此 <img>
會和左右兩側的文字進行對齊, 所以咱們能夠看到 <img>
元素下方有留出空白, 其實是由於對齊而被提高了.
正由於 "基線" 對齊致使 <img>
的行內框被提高致使 "行框" 變大才從而間接的致使 "行框" 的高度增長變爲了 32.4px 而不是圖片的高度 30px, 以下圖所示:
"替換元素" 影響了行框的高度可是並非經過修改父元素的 line-height
的完成的, 或者修改自身的 line-height
來完成的.
<img>
這個 "替換元素" 與其餘 "非替換元素" 沒有什麼不一樣, 它也會繼承 line-height
也能夠設置 line-height
, 可是 line-height
不會影響到它們(svg會受到影響), 例如咱們給 <img>
設置一個 100px 的 line-height
可是這不會影響到他的 "行內框" 的大小:
<body> <p style="font-size:20px;line-height:1">hello <img src="http://temp.im/100x30" style="line-height:100px;"> world</p> </body>
修改後的高度依然和以前的例子高度一致.
不過 line-height
的值能夠被 vertical-align
借用, 這個屬性的百分比單位是基於 line-height
進行計算的, 根據計算的結果在當前的基線上進行上下移動:
img{ line-height:100px; vertical-align:50%; }
這會令 <img>
元素相對於基線向上移動 50px.
對了, 不要忘記 "替換元素" 的內容區域是包括了 margin
padding
和 border
的, 這點和 "非替換元素" 是有區別的:
看到了嗎垂直方向的高度增長了, 仔細觀察你能夠看到 margin-top
和行框(藍色區域)之間存在着一小段距離.
當用戶給某個元素的 display
設置爲 inline-block
屬性的時候他就創造出了一種介於 "內聯元素" 和 "塊級元素" 的混合產物. 這種 "inline-block" 的做用細節實際上和身爲 "替換元素" 例如: <img>
標籤十分類似:
它就像圖像同樣放在一個文本中, 實際上, 行內塊元素會做爲替換元素放在行中. 這說明, 行內塊元素的底端默認地位於文本行的基線上, 並且內部沒有分隔符.在行內塊元素內部, 會像塊級元素同樣設置內容的格式. 就像全部塊級或行內替換元素同樣, 行內塊元素也有屬性
width
和height
, 若是比周圍內容高, 這些屬性會使行高增長.-- css 權威指南(第三版)
例以下面的代碼咱們給 <span>
設置了 display:inline-block
屬性:
<style> #test{ display:inline-block; border:2px solid green; width:6em; margin:5px; padding:5px; color:blue; } </style> <div> helloworld helloworld helloworld <p id="test">emmmmmmm</p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Adipisci, iure, magnam! Quam autem tempora quidem ut. Doloremque luptatibus. Eaque! </div>
這段代碼的結果是:
能夠看到被標記爲 inline-block
的元素的渲染和 "替換元素" 很是相似, 只有一個不一樣就是垂直對齊方式是根據內部文原本進行對齊的, 而不是 "替換元素" 的外邊距的底邊緣.
由於表現和 "替換元素" 同樣當一行中的空間不夠的時候他不會像 "行內框" 那樣行尾斷開進行換行, 而是跑到下一行來獲取空間:
不過請注意inline-block
垂直對齊根據內部文本基線進行對齊能夠會形成意想不到的狀況:
<body> hello world <div style="display:inline-block;width:100px;height:100px;word-wrap:break-word; background-color:red;color:#fff;"> <span> HelloWorld HelloWorld Helloworld </span> </div> <span >Hello World</span> </body>
渲染的結果:
對齊是根據 inline-block
框中的第三個 "hello world" 文字的基線進行對齊的.
https://stackoverflow.com/que...
https://en.wikipedia.org/wiki...
http://www.d.umn.edu/~lcarlso...
https://juejin.im/post/59c9bc...
https://maxdesign.com.au/arti...
https://stackoverflow.com/que...
https://blog.csdn.net/ixygj19...
https://www.cnblogs.com/chaog...
https://developer.mozilla.org...
https://developer.mozilla.org...
https://developer.mozilla.org...
css 權威指南(第三版)
張鑫旭老師的免費視頻課程