From PX to EM

Pixel 是排版最常使用到的單位,但最近我開始改用 em 作為排版主要的單位。預設上 1em = 16px,也就是一個字的寬度。將 px 轉為 em 並不困難,困難的點在於 em 使用的觀念上與 px 並不相同。以下純粹是我自己摸索與實際使用經驗上得到的一點小結論,網路好像找不太到這種 em 的 better practice 文章 XD

Pros

首先,先說明一下為什麼要改用 em 作為單位以及這樣做的好處。前端工程師在切版的時候,通常會從設計師手上拿到圖稿。這圖稿可能是 PSD 或是 AI 檔,壞一點的情況可能拿到純圖檔 (png, jpg...)。

切版的時後常常會遇到一個問題,就是某個區塊的間距到底是多少?是 15px 還是 18px?有經驗的前端工程師可能已經練成了一秒解讀的寫輪眼功力,對這種幾 px 的問題可以立馬轉換。但並不是每個人都有這種功力或是天份,有時候切完會發現版面歪掉無法對齊,或是擠不下所有元件整個破版,就要再回去查圖稿一個一個小地方慢慢調整。

最好的方式還是在切版的時候就盡量百分之百照圖稿切,有錯還可以推給設計師。但是圖稿上不一定會有這些間距的資訊,好一點的設計師可能會好心的幫你把圖稿中所有的間距標出來,或是合作久了的設計師,雙方有個默契在,知道各種間距大概習慣會用多少。但是不巧的是,專案進度常常很趕,設計師出圖都來不及了,哪有空在那邊幫你把每個間距標上去。

於是你可能就要打開 PS/AI 自己去量每個地方的間距,又或著圖稿根本就只是純圖片的檔案,根本沒得量只能賭人品自己猜。但是這樣寫久了可能會發現 css 中充滿各種 15px, 16px, 17px, 18px 看起來像是 Magic Number 的東西,沒有一個間距的準則在。

這也是為什麼我會想要改用 em 而不是用 px 的原因。簡單來說 em 提供了一個基本的寬度單位,不必再去煩惱是 15px 或是 16px,直接 1em 或是 2em 下去就對了。但是排版最麻煩的還是在微調的地方,而使用 em 的時候並不是像 px 那樣 1px 慢慢的調。如果還是用 0.1em, 0.2em 這樣調的話,倒不如繼續回去用 px。

微調 em 要用一招大家都很熟悉的經典演算法,叫做 Binary Search,也就是從 1em 跳到 1.5em, 1.75em, 1.875em 這樣每次都用二分法調整。因為每次都是往前或往後跳一小段間距,太多或太少再往回或往前微調整,就演算法的複雜度來說比線性的調會來得快。另一個好處是因為 1em 預設是 16px,所以二分法一直切下去最多可以切 16 份,也就是 0.0625em,但就我個人經驗上來說,大部份狀況下到 0.125em 就差不多了,只有少數地方可能會用到 0.0625em 的間距。

當然要能夠這樣快速調整 em 有個先決條件就是數學要夠好,例如說 1.75em 是 1.5em + 0.25em,這時候要往回調到 1.75em 與 1.5em 中間的話應該是多少?如果不能很快算出 1.625em 的話其實速度上會慢很多,還要打開計算機慢慢算。當間距小到 0.0625em 的話就更難算了,因為會有 1.6875em 或是 1.8125em 這種東西出現。雖然一開始可能會比較慢,不過其實用久了就會慢慢把這些常用的數字背起來,是會越來越上手的。

Cons

講了這麼多,來說說 em 的必要之惡吧。使用 em 最重要的問題,也是一定會遇到的問題就是 em 會繼承這件事。也就是如果上層定義了 font-size: 14px; 那麼這時下層的 1em 就不再是原先的 16px 了,這會造成兩個地方同樣寫 1.5em 卻對不齊的狀況發生,而在多層繼承下這種狀況會更複雜。

通常可能會想說 em 有問題那我用 rem 就可以解決。事實上用 rem 可能會遇到更多問題,例如瀏覽器支援度。但是其實這個問題有更好而且更簡單的解決方法,只要一個觀念上的轉變。因為 em 會繼承,所以最好的解法就是讓他不要被繼承。如何不要被繼承?只要底下沒有其他元素就不會被繼承了。所以重點就是 font-size 不要下在 DOM Tree 的節點上,只能下在 leaf 上。因為這個原因,我的程式碼裡面常常會出現文字特地用額外的 span 包起來,為的就是要在這個 span 上下 font-size 而不去影響到其他元素。

當然這最好是在專案一開始就統一這麼做,如果想要將現有專案照這個方式改可能會改到吐血。因為一個 font-size 的調整可能就會影響整個版面,所以沒有好的規劃下還是不要輕易嘗試。

理想上這樣就可以完美解決,但實務上有時候還是會避免不了把 font-size 下在節點上。這時其實也不用太慌張,只要 font-size 還是二的倍數,你會發現不同 font-size 的 em 會在某個二分法的位置對齊,這點在使用上會覺得蠻神奇的,但其實就只是因為因數與倍數的關係。不過重點還是要盡量避免繼承這件事發生,會讓樣式比較好維護。

不小心就打了很多,其實大概掌握了幾個原則就可以放心地使用 em 了。我個人目前用起來覺得比 px 感覺好很多,但最終其實還是要看團隊或是專案的狀況,否則混雜 px 跟 em 會更難維護。