如何更愉快地使用em —— 別說你懂CSS相對單位

前段時間試譯了Keith J.Grant的CSS好書《CSS in Depth》,其中的第二章《Working with relative units》,書中對relative units的講解和舉例能夠說至關全面,看完以後發現本身並不太懂CSS相對單位,也但願分享給你們,因此有了這個譯文系列。(如有勘誤或翻譯建議,歡迎 Github PR ^_^)css

《別說你懂CSS相對單位》系列譯文:前端

  1. 如何更愉快地使用em [本文]
  2. 如何更愉快地使用rem
  3. 視口相關單位的應用
  4. 無單位數字和行高
  5. CSS自定義屬性

本文對應的章節目錄:git

  • 2.1 相對單位值的魔力
    • 2.1.1 完美像素設計(pixel-perfect design)的掙扎
    • 2.1.2 完美像素網頁的終結
    • 像素(pixel)、點(point)和pc(pica)
  • 2.2 em和rem
    • 2.2.1 對font-size使用em
      • 當咱們在一個元素內用em同時聲明font-size和其餘屬性
      • 字號收縮問題

CSS提供了不少種方式去定義一個值。你們最熟悉的可能也是最容易使用的就是像素(pixel),這被稱作「絕對單位」。也就是說,5px在不一樣的場景下是同樣的值。而其餘的單位,如em和rem,不是絕對的而是相對的。相對單位的值會根據外部影響因素的變化而變化。例如,2em的值取決於你在哪一個元素使用它(有時甚至是哪一個屬性)。很天然,相對單位使用起來會比較困難。github

開發人員,甚至有經驗的CSS開發人員,每每不喜歡跟相對單位打交道,其中包括臭名昭著的em。em的值能夠被改變的方式彷佛難以預測,沒有px那麼清晰。在本章中,我將揭開相對單位的神祕面紗。首先,我會解釋它們爲CSS帶來的獨特價值,而後我會幫助你更好地理解它們。我會解釋它們的工做原理,也會告訴你怎麼征服它們那看似不可預測的特性。你可讓相對單位爲你所用,正確地運行,它們將讓你的代碼變得更加簡單、靈活和容易使用。web

2.1 相對單位值的魔力

CSS是經過遲邦定(late-binding)的方式把樣式渲染到web頁面上的:內容和它的樣式會在各自的渲染完成以後再合併到一塊兒。比起其餘類型的圖形設計,這給設計過程添加了它們沒有的複雜程度,同時也賦予CSS更強大的能力 —— 一個樣式表可供成百上千個頁面使用。此外,用戶能夠直接改變頁面的最終呈現方式。舉個例子,用戶能夠更改默認字號大小或者調整瀏覽器窗口的大小。瀏覽器

在早期的計算機應用程序開發以及傳統出版行業中,開發人員或出版商清楚知道所在的媒介存在哪些限制。對於一個特定的應用程序,窗口多是400px寬,300px高,或者一個版面多是4英寸寬,6½英寸高。所以,當開發人員佈局應用程序的按鈕和文本時,他們很清楚這些元素能夠作成什麼尺寸,以及在屏幕上還有多少空間能夠留給他們用來處理其餘元素。然而在網頁上,狀況卻不是這樣的。bash

2.1.1 完美像素設計(pixel-perfect design)的掙扎

在web環境下,用戶能夠將瀏覽器窗口設置爲任意大小,且CSS須要去適應它。另外,用戶能夠在一個頁面打開後,再調整它的大小,CSS也須要去適應這些新的約束條件。這說明了在你建立頁面時樣式尚未被調用,而是當頁面在屏幕上渲染時,瀏覽器纔會去計算樣式的規則。less

這給CSS增長了一層抽象的概念。咱們不該該根據理想的情境來設計元素,而是應該聲明一些樣式規則,可讓該元素在任何場景下都能跑通。對於如今的互聯網,你的頁面可能要在一個4英寸的手機屏幕上展現,也可能在一個30英寸的大屏幕上。dom

長久以來,設計師大量使用「完美像素」設計,緩解了這個問題帶來的複雜性。他們會建立一個有着嚴格定義的容器,一般是一個大約800px寬的居中的縱向列。而後在這些限制下他們再進行設計,這跟他們的前輩在原生應用程序或印刷出版物中作的設計或多或少有點相似。工具

2.1.2 完美像素網頁的終結

隨着技術的進步和製造商推出更高分辨率的顯示器,像素完美的設計方式慢慢開始崩潰。在21世紀初期,把頁面設計成1024px寬仍是800px寬,哪一個是更保險的展現策略?開發者針對這個問題討論得不少。而後,咱們又針對可否改爲1280px寬有相似的討論。是時候作個決定了。把咱們網站的內容寬度作得寬一點(相對於落伍的小電腦屏幕),仍是作得窄一點(相對於新出的大屏幕),哪一個選擇更好呢?

當智能手機出現的時候,開發人員終於要(被迫)要中止僞裝每一個人均可以在他們的網站上得到相同的體驗了。無論咱們喜不喜歡,咱們都得放棄已知的多欄定寬(px)佈局,並開始考慮響應式設計。咱們不再能逃避CSS所帶來的抽象概念(abstraction),相反,咱們要去擁抱這項特性。

響應式 —— 在CSS中,這指的針對不一樣大小的瀏覽器窗口,用不一樣的方式響應更新頁面的樣式。咱們要對不一樣尺寸的手機、平板電腦或桌面顯示器多花心思了。咱們將在第8章中詳細介紹響應式設計,但在本章中,我會先給你們介紹一些重要的基礎概念。

增長的抽象概念意味着額外的複雜性。若是我設定一個寬度爲800px的元素,那麼它在一個更小的窗口中會怎麼顯示呢?若是一個橫向菜單不能所有在一行展現完,它又會怎麼展現?在編寫CSS時,你須要可以同時考慮具體狀況以及普適性的問題。若是針對一個特定的問題,你有多種方式能夠解決,那麼你應該選那個在多種不一樣場景下更通用的解決方案。

在抽象概念這個問題上,相對單位是CSS提供的工具之一。與其把字號大小設置爲14px,你能夠把它設置爲與窗口大小成比例縮放。或者,你能夠設置頁面上全部元素是依賴基礎字號大小的變化而變化的,而後用一行代碼就能夠達到調整整個頁面的目的。接下來,咱們來看看CSS提供了哪些方式來實現以上的效果。

像素(pixel)、點(point)和pc(pica)

CSS支持一些絕對長度單位,其中最多見也最基本的是像素(px)。較不常見的絕對單位有毫米(mm,millimeter)、釐米(cm,centimeter)、英寸(in.,inch)、點(pt,point,印刷術語,長度爲1/72 inch)以及pc(pica,印刷術語,長度爲12 points)。若是你想了解其中的計算方式,以上的長度單位均可以直接轉換成另外一個單位:1 inch = 25.4 mm = 2.54 cm = 6 pc = 72 pt = 96 px。所以,16px與12pt(16/96×72)是等價的。設計師一般更熟悉點(point)的使用,而開發人員更習慣於像素,所以在和設計師溝通時,你可能須要在二者之間作一些計算工做。
 
像素這個名字有點誤導性 —— 1 CSS像素並不嚴格等同於顯示器的1像素,在高分辨率顯示器(如「Retina顯示屏」)上尤爲明顯。儘管根據瀏覽器、操做系統和硬件的不一樣,CSS的測量值可能會有細微的差異,但96px老是會大體等於屏幕上的物理1英寸。(儘管有可能會因某些設備或用戶設置而異。)

2.2 em和rem

em是最多見的相對長度單位,這是排版中使用的一種度量方式,基準值是當前元素的字號大小。 在CSS中,1em表示當前元素的字號大小,實際值取決於在哪一個元素上應用。圖2.1展現了一個padding爲1em的div

[ 圖 2.1:padding爲1em的元素(添加虛線是爲了讓padding更明顯)]

模板代碼片斷以下。這套樣式規則定義字號爲16px,也就是元素自己1em表明的值,而後再使用em來聲明元素的padding。 把這段代碼添加到一個新的樣式表裏,在<div class ="padded">下隨手寫些文字,而後到瀏覽器看看效果吧。

代碼片斷 2.1:在padding上使用em

.padded {
  font-size: 16px;
  padding: 1em;          1
}
複製代碼
  • 1 把各個方向的padding的值設置爲字號大小

padding賦值爲1em,乘以字號,獲得一個值爲16px的padding渲染值。重點來了,使用相對單位聲明的值會由瀏覽器轉化爲一個絕對值,咱們稱之爲計算值。

在這個例子裏,將padding改成2em會生成一個32px的計算值。若是同一個元素的另外一個選擇器,用一個不同的字號值去覆蓋它,這會改變em在這個域下的基準值,那麼padding的計算值也會相應變化。

在設置padding、height、width或border-radius等屬性時,使用em可能會很方便,由於若是它們繼承了不一樣的字號大小,或者用戶更改了字體設置,這些屬性會均勻地縮放。

圖2.2展現了兩個不一樣大小的盒子。盒子內的font-sizepaddingborder-radius各不相同。

[ 圖 2.2:有相對大小的padding和border-radius的元素 ]

你能夠經過用em聲明paddingborder-radius來給這些盒子聲明樣式規則。首先給每一個元素設定paddingborder-radius爲1em,而後給每一個盒子指定不一樣的字號,那麼其餘屬性會跟着字號縮放。

在你的HTML代碼裏,建立以下的兩個盒子,類名分別是box-smallbox-large,表明兩個字號修飾符。

[ 代碼片斷 2.2:在不一樣元素上使用em(HTML)]

<span class="box box-small">Small</span>
<span class="box box-large">Large</span>
複製代碼

如今,添加下面的樣式到你的樣式表。這裏使用了em聲明瞭一個盒子。還定義了小字號和大字號的修飾符,指定不一樣的字號大小。

[ 代碼片斷 2.3:在不一樣元素上使用em(CSS)]

.box {
  padding: 1em;
  border-radius: 1em;
  background-color: lightgray;
}

.box-small {
  font-size: 12px;              1
}

.box-large {
  font-size: 18px;              1
}
複製代碼
  • 1 不一樣的字號大小,這會改變元素的em實際值的大小。

這是em一個強大的功能。你能夠定義一個元素的字號大小,而後使用一句簡單的聲明,就能夠經過改變字號大小從而控制整個元素大小縮放。你後面將會建立另一個這樣的例子,不過首先,咱們來討論一下em和字號大小。

2.2.1 對font-size使用em

font-size使用em做爲單位時,它的表現會有點不同。我以前說過,em是以當前元素的字號大小做爲基準值的。可是,若是你把一個元素的字號設爲1.2em的時候,這是什麼意思呢?一個元素的字號大小是不能等於它本身的1.2倍的。相反,在font-size上的em會先從繼承到的字號大小衍生出來。

舉個簡單的例子,見圖2.3。如下展現了一些不一樣字號大小的文字。在代碼片斷2.4,你會用到em來實現。

[ 圖 2.3 以em爲單位的兩種不一樣的字號大小 ]

在你的頁面添加如下代碼片斷。第一行文字,在<body>標籤裏面,它會按body的字號大小渲染。第二部分,口號(slogan),繼承父元素的字號大小。

[ 代碼片斷 2.4 相對font-size的模板 ]

<body>
  We love coffee
  <p class="slogan">We love coffee</p>          1
</body>
複製代碼
  • 1 slogan從繼承了字號大小。

代碼片斷中,CSS代碼片斷聲明瞭body的字號大小。爲了更加清晰,在這裏我用了px來聲明。下一步,你能夠用em來放大slogan的字號大小。

[ 代碼片斷 2.5:在font-size上使用em ]

body {
  font-size: 16px;
}

.slogan {                  1
  font-size: 1.2em;        1
}                          1
複製代碼
  • 1 計算:這個元素繼承到字號,乘以1.2

slogan聲明的字號大小是1.2em,爲了計算轉換成像素值,你須要引用繼承的字號16px,16 * 1.2 = 19.2,因此計算字號值是19.2px。

提示

若是你已經知道以px爲單位的基礎字號大小,但但願把它改用em聲明,下面有個簡單的計算公式:目標em值 = 目標像素值 / 父元素(被繼承元素)像素值。舉個例子,若是你想要一個10px的字號大小,父元素的字號是12px,10 / 12 = 0.8333em。若是你想要16px的字號大小,父元素字號是12px,那麼 16 / 12 = 1.3333em。咱們會在這章裏屢次用到這個計算公式。

有一點對你頗有幫助,對於大多數瀏覽器,默認字號大小是16px。技術上,關鍵字medium會被計算轉換爲16px。

當咱們在一個元素內用em同時聲明font-size和其餘屬性

你已經使用過em聲明font-size了(基於一個繼承的字號大小值)。以及,你也曾經使用em聲明其餘屬性,如paddingborder-radius(基於當前元素的字號大小值)。當你針對同一個元素使用em聲明font-size和其餘屬性的時候,em會變得很神奇。此時瀏覽器必須先計算font-size,而後基於這個值再去計算其餘值。這些屬性聲明的時候使用的是相同的em值,但極可能它們會有不一樣的計算值。

在以前的例子裏,咱們計算到字號大小是19.2px(繼承的16px乘以1.2em)。圖2.4是相同的slogan元素,但有額外的1.2em padding以及爲了讓padding大小更加明顯的灰色背景。能夠看出,paddingfont-size稍微大一些,儘管它倆聲明的時候em值是同樣的。

[ 圖2.4 一個font-size爲1.2em以及padding爲1.2em的元素 ]

如今的狀況是,這個段落從body繼承了16px的字號大小,經過計算獲得值爲19.2px的字號計算值。這意味着,19.2px是1em在當前域的基礎值,而這個值會被用做計算padding的值。對應的CSS代碼在下面,更新你的樣式表並查看你的測試頁面吧。

[ 代碼片斷 2.6 在font-size和padding上使用em ]

body {
  font-size: 16px;
}

.slogan {
  font-size: 1.2em;             1
  padding: 1.2em;               2
  background-color: #ccc;
}
複製代碼
  • 1 賦值爲 19.2 px
  • 2 賦值爲 23.04 px

在這個例子裏,padding的聲明值爲1.2em,乘以19.2px(當前元素的字號大小),計算出23.04px。咱們能夠看到,儘管font-sizepadding聲明時em值是同樣的,但它們的計算值是不同的。

字號收縮問題

當你使用em聲明多層嵌套的元素字號時,會產生意想不到的效果。要弄清楚每一個元素的實際值,首先你須要知道它繼承的父元素的字號大小,若是父元素的字號也是用em聲明的,那麼你須要知道它的父元素的字號大小,在dom樹往上查,以此類推。

當你使用em聲明列表的字號大小,列表嵌套了好幾層,效果就更明顯了。大多數web開發者會發如今他們的職業生涯裏面,圖2.5的列表嵌套形式有點眼熟。文字在逐步縮小!正是由於em帶來的這一類煩人的問題,開發者纔對em避而遠之。

[ 圖 2.5 嵌套列表中的字號縮小現象 ]

當你多層嵌套列表,而每一層聲明的字號大小以em爲單位,字號收縮現象就會發生。在代碼片斷2.7和2.8的例子裏,無序列表的字號是0.8em。這個選擇器對頁面上全部的ul有效,因此當一個列表從另一個列表繼承到字號大小的時候,em就產生複合效果。

[ 代碼片斷 2.7 在列表上使用em ]

body {
  font-size: 16px;
}

ul {
  font-size: .8em;
}
複製代碼

[ 代碼片斷 2.8 多層嵌套的列表 ]

<ul>
  <li>Top level
    <ul>                                    1
      <li>Second level                      1
        <ul>                                2
          <li>Third level                   2
            <ul>                            3
              <li>Fourth level              3
                <ul>
                  <li>Fifth level</li>
                </ul>
              </li>
            </ul>
          </li>
        </ul>
      </li>
    </ul>
  </li>
</ul>
複製代碼
  • 1 這個列表嵌套在第一個列表裏,繼承了它的字號大小
  • 2 而後這個列表又嵌套在另外一個列表裏,繼承了第二個列表的字號大小
  • 3 ……以此類推

每個列表的字號大小是0.8乘以父元素的字號大小。這表明第一個列表的字號大小是12.8px,嵌套的子列表字號大小是10.24px(12.8px * 0.8),第三層列表的是8.192px,如此類推。一樣地,若是你給字號大小的賦值大於1em,相反,文字的字號會一層層變大。咱們想要的效果是像圖2.6同樣,在頂層聲明字號的大小,但下面嵌套層級的列表字號保持不變。

[ 圖 2.6 字號正常的多層嵌套列表 ]

其中一種實現的方式能夠看看代碼片斷2.9。第一個列表的字號大小仍是0.8 em(見示例2.7),第二個選擇器對嵌套在無序列表的無序列表有效 —— 也就是除了第一個無序列表之外的全部無序列表。如今嵌套的列表設定了跟父元素一致的字號大小,正如圖2.6同樣。

[ 代碼片斷 2.9 字號收縮現象的糾正 ]

ul {
  font-size: .8em;
}

ul ul {                1
  font-size: 1em;      1
}  
複製代碼
  • 1 嵌套在列表裏面的列表,應該把字號大小設定爲跟父元素同樣

這能夠解決問題,但不是最優方案。由於你設置了一個字號值,立刻用另外一個選擇器重寫了這個規則。若是你可使用針對嵌套的列表聲明一個特定的選擇器,避免互相覆蓋,會是一個更好的方案。

到如今咱們清楚了,若是你不是一個比較當心的人,你應該遠離em。使用em做爲paddingmargin和元素縮放效果的單位挺好的,但當em趕上font-size時,事情能夠變得很複雜。感謝上天,咱們有個更好的選擇 —— rem。

(未完待續,請期待下一篇《如何更愉快地使用rem》)


《別說你懂CSS相對單位》系列譯文:

  1. 如何更愉快地使用em [本文]
  2. 如何更愉快地使用rem
  3. 視口相關單位的應用
  4. 無單位數字和行高
  5. CSS自定義屬性

章節:

  • 2.1 相對單位值的魔力
    • 2.1.1 完美像素設計(pixel-perfect design)的掙扎
    • 2.1.2 完美像素網頁的終結
    • 像素(pixel)、點(point)和pc(pica)
  • 2.2 em和rem
    • 2.2.1 對font-size使用em
      • 當咱們在一個元素內用em同時聲明font-size和其餘屬性
      • 字號收縮問題
    • 2.2.2 對font-size使用rem
      • 可用性:對font-size使用相對長度單位
  • 2.3 中止使用像素思惟去思考
    • 2.3.1 設置一個合理的字號默認值
    • 2.3.3 讓這個面板變得「響應式」
    • 2.3.3 調整單個組件的大小
  • 2.4 視口相關單位(viewport-relative units)
    • CSS3
    • 2.4.1 在font-size上使用vw
    • 2.4.2 在font-size上使用calc()
  • 2.5 不帶單位的數字(unitless number)和行高(line-height)
  • 2.6 自定義屬性(也叫「CSS變量」)
    • 2.6.1 動態改變自定義屬性的值
    • 2.6.2 經過JavaScript改變自定義屬性的值
    • 2.6.3 初探自定義屬性
  • 總結

原著版權信息:
 
做者:Keith J.Grant
書籍:CSS in Depth
章節:Working with relative units


筆者 @Yuying Wu,前端愛好者 / 鼓勵師 / 新西蘭打工度假 / 鏟屎官。目前就任於某大型電商的B2B前端團隊。

感謝你讀到這裏,對上文如有任何疑問或建議,歡迎留言。

若是你和我同樣喜歡前端,喜歡搗騰獨立博客或者前沿技術,或者有什麼職業疑問,歡迎關注我以及各類交流哈。

獨立博客:wuyuying.com
知乎ID:@Yuying Wu
Github:Yuying Wu

相關文章
相關標籤/搜索