這篇Blog將要討論,在CSS的className中使用連字符“-”還是使用下划線“_”作為分隔符更適合?
在切入主題之前,先看看Google在Webmaster Tools中URL structure章節中所說的一段話:
Consider using punctuation in your URLs. The URL http://www.example.com/green-dress.html is much more useful to us than http://www.example.com/greendress.html. We recommend that you use hyphens (-) instead of underscores (_) in your URLs.
這段話的意思是,出於URL語義化的考慮,Google建議站點URL中使用連字符“-”來代替下划線“_”做分隔符。不知道是否是因為Google的這份文檔,我們可以看到越來越多的國內外網站URL中開始使用“-”來作為分隔符,例如:
http://net.tutsplus.com/articles/general/9-confusing-naming-conventions-for-beginners/
http://stackoverflow.com/questions/1686337/hyphens-or-underscores-in-css-and-html-identifiers
以及我正在使用WordPress編輯的這篇BLOG的編輯地址是:http://yekai.net/wp-admin/post.php?post=338&action=edit
申請過域名的人都知道,一個英文域名中,合法的字符只有數字0-9、字母a-z、符號“-”和“.”兩個。其中“.”號用作域名層級分隔符,“-”號作為單詞分隔符。從牛津詞典中可以看到對連字符hyphen的解釋:
更多hyphen的應用場景,以及hyphen和dash以及minus符號的差異,感興趣的同學可以去看wiki看看。
結論顯而易見,在英語中分隔符號即是hyphen的語義。
這就不難理解,為什么當初在CSS1.0的草案中明確指出,在className中除了連字符“-”以外,包括下划線“_”在內的其他符號必須使用“\”符號轉義之后才能使用。同時也不難理解為什么CSS屬性的寫法是“background-color”而不是“background_color”或者“backgroundColor”了。
然而現實情況卻並非如當初CSS1的規范制訂的那樣完美,很多開發者在寫className中卻因為某些原因,使用了“_”作為分隔符,並將此作為自己的代碼規范。這使得W3C不得不在2001年CSS2的一次修訂版本中將“_”定義為className中的合法字符,無須轉義均可支持。這也是為什么在2001年前的瀏覽器如navigator 4.x、IE 5.x不支持className中的“_”未轉義寫法,而IE6及后來的firefox、chrome均能支持這種寫法。
從某種程度上來說,W3C標准對現實的妥協,也是導致前端開發工程師面對瀏覽器差異化的杯具結局的原因之一。至於W3C支持className中的“_”作為分隔符的原因就不難想象了:正如這種寫法的支持者所說,在JS中下划線“_”才是公認的分隔符。例如,DOM中有一個id為“kaiye”的節點,在IE6中你可以通過document.all.kaiye集合獲取到這個節點的引用。但如果這個ID被命名為“kai-ye”,使用document.all.kai-ye顯然會拋出一個異常,因為基本在所有的編程語言中“-”代表的是“減號運算符”,JS也不例外,正如這篇《Web開發中初學者容易混淆的9個命名約定》中所說。正是由於這點原因,導致在id屬性命名時,開發者通常會避免使用“-”,為了保持代碼風格統一,className中也使用“_”作為分隔符。事實上,W3C並沒有規定class屬性和id屬性命名約定必須相同,className中的“-”分隔符更是和運算符減號“-”風馬牛不相及,CSS不是編程語言又何來減號運算符的沖突問題?
同時這種命名約定卻無形中挖了一個坑:通常在JS的命名約定中,你可以使用 _kaiye 來聲明這是一個私有變量,但如果你在CSS中沿用這種命名習慣使用 _kaiye 來作為className將會導致這段聲明在IE6中無效。不幸的是,我親眼見到有人掉到這個坑里了,並且一定會有更多人因為這種命名約定掉到這個坑里,這也是我堅持不在className中使用“_”最重要的原因。
08年當我剛入職支付寶那會,我跟着小黑做了支付寶的第一個瀏覽器兼容性項目─“Firefox交易流程兼容性項目”。我們修改了上百個交易創建、修改、付款、完成的頁面,修復了其中大量HTML、CSS、JS的兼容性寫法,並同時將記錄匯總成一張bugfix list。結果發現為了使支付寶兼容Firefox,我們對DOM做的最多的修改是,將標簽P修改為DIV,對JS修改最多的是將 document.all 的寫法換成 document.getElementById 。這意味着如果你的產品需要提供更好的用戶體驗,兼容更多的瀏覽器,你應該像許多JS框架那樣使用W3C標准的寫法來編寫你的JS。getElementById就是獲取DOM對象的最佳實踐,而這個方法接受的唯一參數是一個字符串,這個字符串允許你包含任意字符,當然也包括連字符“-”。也就是說,document.all方法將不會出現在一個需要跨瀏覽器支持的產品中,你可以在ID屬性中使用“-”作為分隔符。
Google、Yahoo、淘寶、豆瓣在他們的新CSS代碼規范中推薦使用“-”作為className分隔符,這個自然就不難理解了。
說到這里我們再對“_”的語義進行一番探討。Oxford Dictionary對underscore的定義是underline,在單詞下面畫條線表示強調,這個其實也是<u>標簽的來歷。從wikipedia上可以看到underscore符號最先用於打字機中,用來給某個單詞划線。第二種用法是,當需要打空格,而不能使用空格的時候,會使用underscore來代替。例如URL、filename、編程語言中的變量、表單填寫項繪制等等。從這一點來看,className中的“_”可以給一個“空格”的語義。只是className中真正的空格符,作為class屬性和CSS選擇器時是兩種完全不同的用法。
為了避免“-”運算符的問題,開發者通常使用“_”來作為filename中的分隔符,以方便模塊文件能進行正常的import、include操作。這大概是為何大多數URL仍然使用“_”分隔居多的原因。然而,為了遵守英語通用語義規則,為了提升只懂英文不懂編程的普通人的理解體驗,Google制定了前文所提到的“推薦使用連字符”的SEO建議,MAC OSX操作系統推薦使用空格和連字符進行文件命名,Linux系統以及大多數編程語言的命名都提供了通過引號的方式規避文件名中“-”的沖突問題。而“_”分隔符就像“該字段不能為空”的錯誤提示一樣充滿着程序員的語言習慣。
回到主題,在CSS的className中到底應該使用“-”還是“_”?雖然說“-”更符合語義,看起來代碼更美觀,但“_”也有它存在的合理性─開發者的習慣延續,以及雙擊全選的特性。就像stackoverflow上這個問題的最佳答案所說的那樣:
I think its just personal preference.
而改變一個習慣通常不是一件容易的事情,對自己來說是如此,更別提改變他人。出於我前面所提到的那個坑(通常在JS的命名約定中,你可以使用 _kaiye 來聲明這是一個私有變量,但如果你在CSS中沿用這種命名習慣使用 _kaiye 來作為className將會導致這段聲明在IE6中無效。)以及語義化的原因,在IE6還未消亡的現在,我無法說服自己使用“_”來作分隔符,甚至我覺得,不僅僅是className,CSS、JS、圖片、HTML的filename都應該使用“-”作為分隔符,因為這些資源均是普通用戶看得到的URL。
那么你的習慣呢?如果把自己當作一名前端開發新人,你又會如何選擇呢?
——————–20110613 update:———————-
今天下午借W3C來公司交流的機會,私底下偷偷問Michael Smith,“Hyphen or underscore, which one do you prefer? ”,他的回答是“Neither, I like camelcase.”同時,從ytzong那里得知在CSS-tricks上這個問題討論得也很happy,並且有了一個可供參考的投票結果。