by zhangxinxu from http://www.zhangxinxu.com
本文地址:http://www.zhangxinxu.com/wordpress/?p=5264
一、一切從line-height行高說起
想想看,你CSS構建頁面的時候,默認的字體大小和行高分別是多少?
下面是我統計的一些數據:
- 新浪微博:
12px/1.5
- 騰訊微博:
12px/1.75
- 淘寶網/天貓/騰訊微雲:
12px/1.5
- 京東:
12px/150%
計算下來,基本行高要么是18像素,要么是21像素~
我想,大多數小伙伴應該沒關注過這方面的細節,基本行高大致就可以,取1.5
方便計算,1.75
呢似乎也無傷大雅。
當下的網頁早已告別當初就只能瀏覽信息的那種狀態,頁面結構更加復雜,大段描述文字的情況只占少數,因此,行高的角色有點從閱讀體驗層面轉換為更方便的計算或者其他什么角色。
這里的“其他什么角色”看似平淡無奇的一句話,其實才是本文的主角。在本文,行高擔任了網頁垂直格柵基准的角色!
我們以前可能聽過網頁格柵布局,老實講,我對水平格柵一點興趣也沒有,幾百篇CSS文章我也從來沒有介紹過,因為跟自己的布局理念不符;但是,我今天倒是要提一提垂直格柵!
頁面內容往往是自上而下瀑布式的呈現,內容千變萬化,元素的高度也是變幻莫測,因此對於垂直方向,所謂格柵,幾乎是無稽之談。確實是這樣,但是,局部的格柵有時候會讓我們的頁面變得更加規范,以及可以讓我們的工作更加輕松。
而這一切,就要從行高說起。我們以前寫頁面,都是設置字體大小以及行高值,確定單行文本所占據的高度內容;而我們這里,則逆向思維,我們希望頁面基本文字所占據的高度是20
像素,則我們的行高應該是?
現在是大屏時代,假設我們的默認字號大小是14
像素,我們計算下:20/14≈1.4285714285714286
,四舍五入的結果,於是得到:
body { line-height: 1.42857; font-size: 14px; }
不好意思,給大家下套子了,注意了,在CSS中,行高計算的時候,一定不要向下四舍五入,而要向上。類似上面的代碼,雖然14*1.42857
近乎就是20像素,但是,不好意思,最后還是以19像素的高度呈現,在Chrome瀏覽器下就是如此!
因此,實際的設置應該是:
body { line-height: 1.42858; font-size: 14px; }
於是,我們就得到了一個20像素為基准的網頁布局環境了,此時,普通一行文字的高度就是20像素,那又有什么好處呢?
單一來看,20像素的高度單元和21像素似乎沒什么差別,但是,如果放在一個完整的體系里面,價值就能很好地體現了!
二、20像素為基准的20*20像素的小圖標策略
基本上每一個網站都離不開小圖標,國際通用的圖形語言,對於一個網站而言,無論是體驗還是辨識度都是必不可缺的。
目前而言,絕大多數網站還是處於12像素字體時代,設計師設計的圖標都是按照16*16像素規格設計的偏多;不太專業的設計師可能會14~20像素之間搖擺。
反正不管怎樣,最后(加上sprite工具盛行)我們圖形在網頁中的尺寸基本上就是16px*16px
:
.icon-hi { display: inline-block; width: 16px; height: 16px; }
當然,17px*18px
也是很常見的:
.icon-hi { display: inline-block; width: 17px; height: 18px; }
這種一小圖標真實尺寸構建CSS代碼的方式有3個比較大的問題:
- 與后面文字的對齊
- 點擊區域大小
- 重復冗余的CSS代碼
1. 與后面文字的對齊
由於vertical-align
屬性的兼容性,以及vertical-align:middle
並不是嚴格意義的垂直居中,因此,小圖標+文字的對齊,基本上都要針對不同瀏覽器加個hack補丁;在加上,如果你的圖標尺寸一會兒16像素,一會兒18像素,顯然,沒法通過全局一個設置使得整站的小圖標和文字都對齊良好!
例如,騰訊微博這里,圖標就是16像素尺寸,然后,一些五花八門的處理:
很多補丁,很多CSS處理,里面圖標使用了absolute絕對定位,這倒是處理兼容挺不錯的方法,但是,顯然不具有普遍適用性。
2. 點擊區域大小
有時候,我們的小圖標直接就是點擊按鈕,此時,如果你的尺寸就是16像素*16像素,會不會點不准的概率就上升了,如果圖標是20px*20px呢?
3. 重復冗余的CSS代碼
當下類似grunt-spritesmith的小圖標合並工具基本成了前端團隊的標配,而根據我的觀察,基本上,大家都是設計師給的圖標直接扔到文件夾里面進行合並,於是,產出的代碼基本上就是width
/height
/background-position
的模式,然而,可能里面70%寬高都是16像素,20%是18像素,還有10%是其他小尺寸,也就是,其實很多CSS代碼是可以合並的,然而,都浪費了。
如下生成less代碼截圖(源自真實項目):
以上這些問題實際上一個對策就可以搞定,就是所有圖標統一按照20px*20px的標准處理!
你想啊,我們網頁文字基礎高度是20像素,圖標也是20像素高,天然對齊,問題1解決;20*20的點擊區域對吧,顯然比16*16要大,問題2解決;所有圖標都是20*20的尺寸范圍內,所有width
/height
都可以合並,大大減少CSS代碼,問題3也搞定了!
如下圖CSS生成模板示意:
————-低調的分隔線————-
然而,實際上的處理要比上面說的復雜和深奧的多!
圖標和文字天然對齊
按照我們直觀的認知,兩個元素都是20像素高,都在自己的垂直范圍內居中,那這兩個元素應該是在一個水平線上的。實際上真的是這樣嗎?是的,但是,注意這里的但是,是有條件限制的!
在“CSS深入理解vertical-align和line-height的基友關系”一文中,其中就已經提及過:
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里面既沒有line boxes或者本身’overflow’屬性的計算值而不是’visible’, 這種情況下基線是margin底邊緣。
翻譯成白話就是:
如果inline-block水平元素’overflow’不是’visible’,或者里面沒有內聯元素(圖片、文字之類),則整個元素的基線就是自身的下邊緣;否則,基線就是里面最后一行圖文元素的基線(
這是我們需要的)。
有點不太理解?沒關系,不是本文的重點。你只要知道,我們要想20像素高的圖標和20像素高的文字天然對齊顯示,需要滿足這兩個條件:
overflow
屬性值除了visible
都不行;- 里面需要有不加修飾的文本內容;
所以,下面兩種情況都是淘汰的!
.icon { display: inline-block; width: 20px; height: 20px; background: ... overflow: hidden; } <i class="icon"></i> .icon { display: inline-block; width: 20px; height: 20px; background: ... }
第一種情況是overflow:hidden
拖后腿了;第二種情況是<i>
標簽里面是空大屁,基線還是元素底邊緣而不是里面的文字(如果有)。
因此,要想實現小圖標天然對齊,我們不能有overflow:hidden
同時HTML標簽內部有文本內容,我靠,好多限制,貌似很煩啊,然而,經過本人的實踐,是可以有CSS代碼段滿足各種場景的對齊效果的,如下:
.icon { display: inline-block; width:20px; height:20px; background: ...; white-space:nowrap; letter-spacing: -1em; text-indent: -99em; color: transparent; /* IE7 */ *text-indent: 0; *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '\3000'); } .icon:before { /* 偽元素插入空格文本 */ content: '\3000'; }
您可以狠狠地點擊這里:小圖標文字對齊的終極解決方案demo
結果,無論是空標簽HTML,還是內置可訪問性提示文字的HTML,都是對齊效果棒棒噠!
<i class="icon"></i> <a href="javascript:" class="icon">刪除</a>
而且,就算文字的字號大小變化,例如14px
→16px
圖標和文字也是對齊良好的,因為,對齊的本質是圖標元素里面的文字和后面的文字對齊,文字和文字對齊,自然是天然對齊的,千古難題就這么有了解決方案,以前的CSS hack啊,什么vertical-align
控制,還有margin
負值偏移都是浮雲了!
圖標20*20尺寸擴展grunt工具
設計師設計的圖標都是16px~20px不等,CSS代碼都是Grunt工具生成的,我們很難簡單控制讓所有圖標都是20*20的區域大小。除非,我們對所有的小圖標在導出的時候,手動擴展畫布到20px*20px。
親,什么年代了,又不是搞藝術品,手工勞作年代過去了,直接上工具。
我基於GM搞了個20像素以下小圖標自動擴展為20像素大小圖片的Grunt工具:https://github.com/zhangxinxu/canvasExpand
精力有限,這個小項目還沒細整就扔上去了,可以看到,很多模板生成的文字我還沒來得及改。
window用戶記得要安裝ImageMagick.exe,安裝時候記得勾上那個全局變量什么東西的。
如果有什么問題,歡迎……不要來打擾我,忙,自己想辦法,么么噠~~
圖標的重心像素級處理
有些圖標,雖然設計師給的尺寸是標准的,沒有多余像素,但是,可能圖標本身的形狀並不是對稱的,尤其上下,這就會導致圖標的重心會有些偏上或者偏下,導致和后面的文字呈現的時候,雖然真實尺寸是對齊的,但是視覺感覺卻是不在一條線上。如果要求很高,可以讓設計師或UI工程師自己微調下,一般1像素就夠了,當然,是調整圖片,例如,重心低的,下面多1像素高度的透明區域。
三、40像素高度的UI組件體系
前面提到過,20像素的基准行高要在體系中才能大放異彩,而這個體系的另一個非常重要的成員就是頁面的基本UI組件們!
所有的按鈕均是40像素高度,所有的輸入框都是40像素高度,所有的下拉框、時間選擇框都是40像素高度;
上圖截自“基於原生HTML的UI組件開發”一文那個展示前端分離的例子:QQ公眾平台UI組件下的前端分離demo
由於我們的基准文字高度是20像素,因此,左邊文字距離頂部的間距,就是標准的10像素!
這就使得我們網頁中無論是大模塊之間的間距,還是小的文字和空間之間的間距;無論是水平的間距還是垂直的間距,全部都是標准的5像素的倍數。從而讓我們所有的大小模塊的實際高度都是10的倍數(padding-top + line-height*行數 + padding-bottom)。
換句話說,我們以20像素為基准進行布局和UI組件設計,使得我們的網頁間距標准化了,無形之中會讓我們頁面的排版更專業,同時也讓zxx.lib.css的利用率提升了。
如果我們進一步深究按鈕或者輸入框的實現細節,你會發現,其CSS實現本身就是按照20像素為基准的策略進行實現的:
//zxx: 擦,一看代碼,發現按鈕直接行高控制的,失策失策,我回去就調整下,這其實是有問題的,適用性大了折扣,因為沒有遇到按鈕中有圖標的設計情境,所以沒有暴露出來。更好實現應該和上面輸入框一行,20像素行高,使用padding實現最終的40像素高度。