云端漂移 2019-06-09
这篇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,并且有了一个可供参考的投票结果。