A Guide to CSS Rules - CSS 規(guī)則書寫不完全指南
很久之前有嘗試整理過一份 CSS 命名書寫規(guī)范,CSSWritingRules[1]。
本文在上文的基礎下,再提供多一些建議,可選擇遵循使用或者部分遵循使用,視團隊情況及業(yè)務特性而定。大部分規(guī)則翻譯自 CSSLint-- Wiki[2]。
從 CSSLint 的規(guī)則中,我們可以窺探到很多有意思的的 CSS 細節(jié),可幫助我們更好的理解 CSS 以及寫出兼容性更好的 CSS 代碼。
- 這只是一份指南,不是一份標準。
可能/潛在的錯誤寫法
下面的一些規(guī)則是一些潛在會導致一些意料之外的錯誤的 CSS 書寫方式。
留意盒子的尺寸(Beware of box model size)
該規(guī)則主要是針對盒子的高寬而言,考慮下面這種情況:
- .mybox {
- border: 1px solid black;
- padding: 5px;
- width: 100px;
- }
mybox 的元素寬度可能會被誤認為 100px。但實際上,寬度是 112px。這是因為盒子寬度最終由content、padding、border 的寬度相加而得。
建議的寫法:
- .mybox {
- box-sizing: border-box;
- border: 1px solid black;
- padding: 5px;
- width: 100px;
- }
建議的規(guī)則:
- width 被與 border, border-left, border-right, padding, padding-left, padding-right 屬性同時使用時,指定 box-sizing ;
- height 被與 border,border-top,border-bottom,padding,padding-top,padding-bottom 屬性同時使用時,指定 box-sizing 。
display 匹配屬性(display-property-grouping)
當元素設定不同的 display 時,部分規(guī)則可能無效。
當 display:inline 時, width, height, margin-top, margin-bottom 和 float 屬性將無法生效,因為內聯(lián)元素盒子模型不是一個標準盒子模型,這些屬性也就無法生效。
當然,不止上述的 display:inline,還有一些,具體而言,
建議的規(guī)則:
- display:inline 不與 width, height, margin, margin-top, margin-bottom, float 同時使用;
- display:inline-block 不與 float 同時使用;
- display:block 不與 vertical-align 同時使用;
- display:table-* 不與 margin 或 float 同時使用。
不允許屬性重復(duplicate-properties)
這個很好理解,不允許同一個樣式規(guī)則中,出現(xiàn)重復定義的屬性。例如:
- .mybox {
- width: 100px;
- width: 120px;
- }
當然,也存在例外,定義同個屬性可以用來實現(xiàn)一些漸進增強功能,舉個例子:
- .mybox {
- background: #fff;
- background: rgba(255, 255, 255, 0.5);
- }
對于不支持 RGBA 色彩展示的瀏覽器,將會回退使用第一條定義的規(guī)則 background: #fff 。
不建議的寫法:
- /* properties with the same value */
- .mybox {
- border: 1px solid black;
- border: 1px solid black;
- }
- /* properties separated by another property */
- .mybox {
- border: 1px solid black;
- color: green;
- border: 1px solid red;
- }
允許的寫法:
- /* one after another with different values */
- .mybox {
- border: 1px solid black;
- border: 1px solid red;
- }
建議的規(guī)則:
不允許出現(xiàn)兩次且值相同的屬性;
不允許同個屬性出現(xiàn)兩次且中間被至少一個其它的屬性所隔開。
不允許空規(guī)則(empty-rules)
空規(guī)則就是不包含任意屬性(沒有定義樣式屬性) ,如下:
- .foo {}
空規(guī)則的出現(xiàn)可能是因為重構了樣式而忘記了刪除冗余代碼造成的。消除空規(guī)則可以縮小樣式文件大小和精簡瀏覽器待處理的樣式信息。
建議的規(guī)則:
1.代碼中不包含空樣式規(guī)則
使用已知的屬性(known-properties)
CSS 可使用的屬性變得越來越多,本規(guī)則檢測屬性名稱是否正確。此規(guī)則將檢查每個使用的屬性名稱以確保其是已知的屬性。
當然,以 - 前綴開始的瀏覽器專有屬性將被忽略,因為前綴會添加各個瀏覽器版本屬性上,而這些屬性沒有一個參考標準。
此規(guī)則不僅會檢查屬性名稱,也會檢查屬性對應的值是否與其匹配。
建議的規(guī)則:
2.樣式中使用標準的屬性及屬性值
兼容性
不允許負文本縮進(Disallow negative text indent)
此規(guī)則意在找出 CSS 代碼中使用 text-indent 的潛在問題。
文本負縮進通常當作輔助的目的,來隱藏在屏幕上的文字。使用場景之一就是作為圖像替換技術,使用文本負縮進,可確保屏幕閱讀器在文本沒有顯示在屏幕中時也能讀取其數(shù)據(jù)。
此技巧通常使用很大的負單位數(shù)值,如 -999px 或 -9999px,如下:
- .mybox {
- background: url(bg.png) no-repeat;
- text-indent: -9999px;
- }
此帶有技巧性的縮進,允許背景圖片展示給普通用戶的同時,也確保了屏幕閱讀器能順利解析內聯(lián)的文本信息。
當文本負縮進使用在橫向視圖頁面時,會引起一定的麻煩,因為會出現(xiàn)一個很長的橫向滾動條。此問題可以通過添加 direction:ltr 來解決,如下:
- .mybox {
- background: url(bg.png) no-repeat;
- + direction: ltr;
- text-indent: -9999px;
- }
建議的規(guī)則:
1.當使用負文本縮進的時候,配合 direction: ltr 一起使用。
使用瀏覽器兼容前綴(Require compatible vendor prefixes)
瀏覽器兼容前綴是一個屬性從提案到成為標準演進過程導致的問題。
以漸變 gradient 為例,2011年12月份,CSS漸變的標準定義還未定稿,也就是說,彼時想跨瀏覽器實現(xiàn)色彩漸變,需要使用很多不同版的游覽器前綴。CSS漸變一共有有五種不同的瀏覽器前綴。
- -ms-linear-gradient and -ms-radial-gradient for Internet Explorer 10+
- -moz-linear-gradient and -moz-radial-gradient for Firefox 3.6+
- -o-linear-gradient and -o-radial-gradient for Opera 11.10+
- -webkit-linear-gradient and -webkit-radial-gradient for Safari 5+ and Chrome
- -webkit-gradient for Safari 4+ and Chrome (aka "Old WebKit")
該規(guī)則要求我們使用漸變時,包含定義所有瀏覽器前綴。
當然,如今標準已經(jīng)統(tǒng)一,而且到今天,我們書寫 CSS 添加瀏覽器前綴幾乎不再是人工添加。都應該使用 autoprefixer ,解放生產(chǎn)力,還有一些類似的前綴兼容問題,例如 display: flex 等等,可點擊查看:
展開查看建議追加多內核前綴
- 隨著 CSS 的發(fā)展,這個表肯定是無法囊括全部的,所以最好的方式還是 autoprefixer ,使用工具添加瀏覽器前綴。
建議的規(guī)則:
1.盡量使用 autoprefixer 來編譯的你的 CSS 代碼,使用工具去替代人工添加瀏覽器前綴。
使用備用色彩值(Require fallback colors)
此規(guī)則意在確保在所有的瀏覽器上都能顯示合適的顏色。建議在使用 CSS3 顏色表示法 rgba(), hsl(), and hsla() 時,使用一個備份顏色確保顏色值在低版本瀏覽器上能正常顯示,像這樣:
- .mybox {
- color: red;
- color: rgba(255, 0, 0, 0.5);
- }
建議的規(guī)則:
指定顏色屬性,使用了 rgba(), hsl(), hsla() 顏色值時,在該屬性定義前使用針對舊版瀏覽器的 color 顏色格式。
不再使用針對舊版本 IE 的 hack 方式
在早幾年,舊版本 IE 瀏覽器仍是不得不兼容的時代,我們的 CSS 代碼會存在很多 *, _等,類似這樣:
- {
- background-color:yellow\0; /*ie8*/
- +background-color:pink; /*ie7*/
- *background-color:pink; /*ie7*/
- _background-color:orange; /*ie6*/
- }
在 IE8- 逐漸退出歷史舞臺的今天,如果業(yè)務已經(jīng)完全拋棄 IE8-,那么就應該不再使用這些針對 IE 的 hack 方式。
建議的規(guī)則:
1.不再使用 +,_,*,\0 等這些針對 IE 的 hack 方式
CSS 性能
不使用過多網(wǎng)絡字體(Don't use too many web fonts)
這個很好理解,@font-face 的出現(xiàn)讓我們可以讓用戶使用任何字體,不必拘泥于"web-safe"的字體之一。
但是,字體文件本身是很大的,以及部分瀏覽器在下載字體文件時,不會實時渲染,就給使用網(wǎng)絡字體的同時,帶來了顯示性能的隱患。
因此建議,使用 @font-face 使用 web-fonts 不易過多。
建議的規(guī)則:
使用少于 5 次網(wǎng)絡字體 @font-face 引用。
5 這個次數(shù)是 CSSLint 的建議,個人認為實際使用中這個值應該更低。
不使用@import
@import 命令用于在 CSS 文件中引用其它的 CSS 文件,如下:
- @import url(more.css);
- @import url(andmore.css);
- a {
- color: black;
- }
當瀏覽器解析此代碼時,會在每個 @import 后開始下載指定的文件,從而停止執(zhí)行后面的代碼。
也就是說在 @import 指定的文件未下載完成前,瀏覽器不會同時下載其它的樣式文件,從而失去了并行下載 CSS 的優(yōu)勢,且會造成頁面的閃爍。
建議的規(guī)則:
1.不在 CSS 代碼中使用 @import
當然,這里的 @import 是指編譯之后的 CSS 文件不出現(xiàn),未編譯的 CSS 文件不受此限制。
謹慎使用屬性選擇器(Disallow selectors that look like regular expressions)
CSS3 屬性選擇器更新之后,使得 CSS 有了一種類似正則匹配的能力,屬性選擇器詳見:CSS 屬性選擇器的深入挖掘[3],像這樣:
- [attr|=val] : 選擇attr屬性的值是 val 或值以 val- 開頭的元素(注意,這里的 “-” 不是一個錯誤,這是用來處理語言編碼的)。
- [attr^=val] : 選擇attr屬性的值以 val 開頭(包括 val)的元素。
- [attr$=val] : 選擇attr屬性的值以 val 結尾(包括 val)的元素。
- [attr*=val] : 選擇attr屬性的值中包含子字符串 val 的元素(一個子字符串就是一個字符串的一部分而已,例如,”cat“ 是 字符串 ”caterpillar“ 的子字符串
選擇一個 img 標簽,它含有 title 屬性,并且包含類名為 logo 的元素。
- img[title][class~=logo]{
- ...
- }
屬性選擇器帶來匹配便利的同時,由于這些復雜的屬性選擇器都須通過一遍又一遍的計算來匹配對應屬性值,從而確保最終的顯示效果正確。為此,CSS需要消耗更多的時間,來計算整個頁面的顯示效果。
建議的規(guī)則:
1.盡量少的使用屬性選擇器,如果確定要使用,應該要意識到該選擇器帶來的開銷比一些常規(guī)選擇器更大
謹慎使用通配符 * (Disallow universal selector)
通用選擇器 (*) 匹配所有元素。盡管每次都能很方便的選擇一組元素,但如果將其作為選擇器的核心部分(選擇器位置的最右側) 則會造成性能問題。舉個例子,如下的規(guī)則形式應該避免使用:
- .mybox * {
- background: #fff;
- color: #000;
- background: rgba(255, 255, 255, 0.5);
- }
瀏覽器解析 CSS 的規(guī)則按照從右至左的順序解析選擇器的,因此這個規(guī)則將首先匹配文檔中的所有元素。然后逐一檢測這些元素是否匹配右邊開始的下一級規(guī)則,即是否擁有祖先樣式mybox。如果包含* 的選擇器越復雜,其解析的時間越久。
建議的規(guī)則:
1.應該謹慎使用通用選擇符 *,如果必須要使用,也應該盡量避免將其放置選擇器的最右側。
謹慎使用未定義的屬性選擇器(Disallow unqualified attribute selectors)
HTML5 允許在 HTML 標簽中創(chuàng)建自定義屬性。然而,與上一條規(guī)則類似,如 [type=text],首先匹配所有元素,然后檢查各屬性。這意味著未定義屬性選擇器和通用選擇器一樣都有著相同性能問題。
和通用選擇器相似,未定義屬性選擇器作為選擇器的核心部分(選擇器最右側)時,會造成性能問題。像這樣:
- .mybox [type=text] {
- background: #fff;
- color: #000;
- background: rgba(255, 255, 255, 0.5);
- }
建議的規(guī)則:
1.盡量避免將屬性選擇器其放置在選擇器的最右側。
使用簡寫屬性(Require shorthand properties)
此規(guī)則建議,當可通過簡寫屬性來減少文件體積時,應當盡量使用簡寫方式,像這樣:
- .mybox {
- margin-left: 10px;
- margin-right: 10px;
- margin-top: 20px;
- margin-bottom: 30px;
- }
應該替換為:
- .mybox {
- margin: 20px 10px 30px;
- }
建議的規(guī)則:
1.當可通過簡寫屬性來減少文件體積時,應當盡量使用屬性的簡寫方式
不允許重復背景圖片定義(Disallow duplicate background images)
如果你有多個樣式需要使用同一背景圖片,那么最好聲明一個包含此圖片地址的通用樣式類。接著將這個類添加至需要使用的元素之上。請看下面代碼:
- .heart-icon {
- background: url(sprite.png) -16px 0 no-repeat;
- }
- .task-icon {
- background: url(sprite.png) -32px 0 no-repeat;
- }
在兩個類中重復定義了背景圖片地址。造成了冗余代碼,同時也增加了修改的成本。
如果需要修改圖片的名字,很容易造成忘記同時修改文件中兩處圖片地址。比較好的方式是抽取一個圖片地址類作為復用類,然后將此類添加至原有HTML元素上。像這樣:
- .icons {
- background: url(sprite.png) no-repeat;
- }
- .heart-icon {
- background-position: -16px 0;
- }
- .task-icon {
- background-position: -32px 0;
- }
- <div class="icons heart-icon">A</div>
- <div class="icons task-icon">B</div>
建議的規(guī)則:
1.在需要使用重復的背景圖片時,應該定義一個公用類進行復用
可維護性和重復性(Maintainability & Duplication)
盡量少的使用浮動 float(Disallow too many floats)
float 屬性是 CSS 中實現(xiàn)多列布局廣受歡迎的方式。在項目中, float 元素被用來創(chuàng)建不同的頁面布局。如果此時改變布局,則會使得CSS代碼十分脆弱,難以維護。
在如今,我們有更好的方式去實現(xiàn)網(wǎng)格化布局:flex 及 grid 。
建議的規(guī)則:
1.盡量少的使用 float 去進行頁面布局,如果兼容性允許,應該使用 display: flex 或者 display: grid 進行替代
不使用過多的字體大小聲明(Don't use too many font size declarations)
一個利于維護的站點,通常都有通用的字體集。某類字體的大小往往定義了一個代表其含義的抽象類,以便運用到站點的各個使用場景。
如果未抽取出公用類。會導致書寫 CSS 時頻繁的使用 font-size 來使元素大小按預期顯示。這就帶來了一個問題,當設計的字體大小改變后,我們需要改變樣式中所有設計的字體大小。而抽提取公用類時,只用改變類中定義的大小即可做到全局調整。像這樣:
- .small {
- font-size: 8px;
- }
- .medium {
- font-size: 11px;
- }
- .large {
- font-size: 14px;
- }
在你的項目中使用以上類時,能確保字體大小的一致性貫穿始終,也限制了 font-size 在 CSS 文件中出現(xiàn)的次數(shù)。如果需要某類字體大小,此時,只需要改變一處字體大小的設置,就可實現(xiàn)之前需要修改多處的效果。
建議的規(guī)則:
1.不使用過多的字體大小聲明,通過定義不同類型的字體類進行字體大小的復用
盡量少的使用 ID 選擇器進行樣式定義(Disallow IDs in selectors)
CSS 的好處之一就是可在多處復用樣式規(guī)則。當你開始使用 ID 選擇器時,就不經(jīng)意間將樣式局限在了單個元素上。假設你的代碼如下:
- #header a {
- color: black;
- }
這個樣式只會在 ID 為 header 下的 a 標簽 起效。但假設現(xiàn)在你想在頁面中的另外一個模塊中也使用同樣的樣式,你只能重新再定義一個類來實現(xiàn)同樣的效果,如下:
- .callout a {
- color: black;
- }
細想,其實這里,本意應該是只用一個樣式就足夠了:
- .callout a {
- color: black;
- }
最后,你可能將不再需要使用 ID 選擇器而使用類選擇器取代其效果。棄用 ID 選擇器后,你將最大釋放CSS 的復用能力。
建議的規(guī)則:
1.盡量少的使用 ID 選擇器進行樣式定義
最后
沒有最好的規(guī)則,只用適合的規(guī)則。
關于 CSS 的書寫命名使用標準一直有很多不同的觀點,對待所謂的規(guī)范最好的方式不是人云亦云,拿來就用,而是應該結合實際情況及需求,取長補短,取其精華去其糟粕。
好了,本文到此結束,希望對你有幫助 :)
參考資料
[1]CSSWritingRules: https://github.com/chokcoco/CSSWritingRules
[2]CSSLint-- Wiki: https://github.com/CSSLint/csslint/wiki/Rules
[3]CSS 屬性選擇器的深入挖掘: https://github.com/chokcoco/iCSS/issues/65