(点选下方社会公众号,可加速高度关注)
英语:Keith J. Grant 原文:科刺剑译者/KING
zcfy.cc/article/thoughts-on-self-documenting-css
Robert C. Martin写的《Clean Code》是我读过的最合适的程式设计书刊众所周知,若没读过,所推荐你将它重新加入引文。
注解就意味著标识符难以自表明 —— Robert C. Martin
Martin在该文详尽讨论了标识符注解,我不能全然多次重复他不然。具体来说,他的原意是,那些注解是或许会落伍的。程序代码时能忽略注解,因此难以确保那些表明注解会精确的叙述标识符促进作用。因此最合适的形式是让标识符自表明,这般,依照标识符方法论
思索如下表所示标识符:
// Check to see if the employee is eligible for full benefits
全数社会福利
if ((employee.flags & HOURLY_FLAG) && (employee.age > 65)) {
…
}
注解有用么?当然有用,但下面的形式可能更好:
if (employee.isEligibleForFullBenefits()) {
…
}
标识符需要“言行一致”,注解是能够被命名良好的函数或变量取代的。Martin的原意并不是说永不使用注解,而是应该尽量避免写注解,注解就意味著标识符难以自表明。
那么对CSS而言呢?
我非常赞同Martin关于注解的看法。当涉及到声明式的语言如CSS时,就发现了一些有趣的地方。声明式语言式必须符合对应格式的,而CSS选择器基本是由HTML结构决定的。对这种标识符结构,我们能做的不多,这是否意味著CSS标识符必须注解满天飞?
额,也许吧。有很多的理由使用注解,且注解的写法也有很多。让我们来看一些注解,思索那些注解是否应该添加。先从答案显然的开始吧,然后一步步深入到不那么好判断的。
不好:多此一举的注解
任何语言,多此一举的注解都是多余的,如下表所示的示例出自Bootstrap3的早期版本:
// Addresses
address {…}
显然,address是关于地址的选择器
// Unordered and Ordered lists
ul,
ol {…}
还有?
// Blockquotes
blockquote {…}
赶紧停!
千万不要写那种注解,赶紧删掉那些多余的东西,它仅仅是在多次重复标识符而已。当然,新版本的Bootstrap已经删除掉大部分多此一举的无用注解了。
不好: 块分隔注解
对CSS而言,块分隔注解是非常特殊的,如下表所示:
/* —————–
* TOOLTIPS
* —————– */
这种注解能把我逼疯。我能想到为甚么会写下这种注解:有时候我们的CSS会写得非常长,当在超过千行的文件内查找时,就需要这种带特殊标志的注解来帮助加速搜索。
但事实上,很长很长的CSS文件已经不再流行了。若你的项目确实需要这种很大的CSS文件,它应该是由多个小的部分,通过CSS预处理工具组合而成的。
不好:解释语法
又要用Bootstrap举例了,以下标识符出自 _tooltips.scss:
// Allow breaking very long words so they dont overflow the tooltips bounds
// 设置长单词换行
word–wrap: break–word;
这种形式和“多此一举的注解”类似,注解解释word-wrap属性的促进作用。这里有一篇文章讲到这种注解为甚么不需要的原因,注解应该解释“为甚么”,而不是“是甚么”,即表明原因而不是表明促进作用(Why, not what)。
此处有一个例外,由于CSS有很多属性,也许有些属性是你全然不知道的,那么你用这种注解是正常的。
不好:对库进行介绍
如下表所示是Bootstrap tooltips.scss文件的另一段注解:
// Our parent element can be arbitrary since tooltips are by default inserted as a
// sibling of their target element. So reset our font and text properties to avoid
// inheriting weird values.
// 由于提示框会被默认插入到目标元素后作为一个兄弟元素,
// 因此需要重置提示框的字体属性避免从父元素继承样式影响。
@include reset–text();
font–size: $font–size–sm;
这条注解很有原意,看起来似乎并不违反“表明原因而不是表明促进作用?”规则,它表明由于可能会被一些意料之外的继承字体属性影响,因此用导入的形式来重置字体属性。
但进一步来看,显然在文件头导入重置样式的唯一的解释是担心被继承样式影响。
因此,我认为这种注解也是不需要的,因为导入函数名字已经表明用途了,尽量让函数名切合促进作用,如reset-inherited-font或类似的名字,不仅清晰表明了用途还是表明了原因。这个是一个函数调用,函数名已经足够解释了。优先用这种形式来表明用途可以替代一些注解。
CSS预处理器让CSS更接近传统程式设计语言。尽可能使用命名良好且有意义的变量和函数,这样能让标识符更清晰。
不好: 落伍的注解
.dropdown–header {
…
white–space: nowrap; // as with > li > a
}
“as with > li > a”是甚么原意?我第一反应是也许在文件中还有一个> li > a的选择器,而这行标识符是指那个选择器。也许文件中有一段注解会专门解释为何这样写,但我将文件重头到尾都看了一边,发现并没这个选择器。文件只有一个.dropdown-item选择器下有一个nowrap属性,也许是是指这个?或者也许这段注解是指某行已经被删除的标识符或引入其他文件中的标识符?若想要彻底弄清楚这个注解的促进作用,唯一的方法是翻遍整个git记录了吧。
这是一个落伍的注解,也许它以前是有用的,但却长时间没用到,因此落伍了。这也许是为甚么Robert Martin对注解的看法:若注解对应的标识符更新了注解就没用了,甚至更糟糕,注解可能会将你引到错误的方向。若发现这样的注解,一定要删掉。它全然没用,而且会浪费时间去思索到底有啥用?
有时有用的:有特殊意义的注解
如下表所示是一段带注解的标识符:
.dropdown–item {
display: block;
width: 100%; // For `<button>`s
padding: $dropdown–item–padding–y $dropdown–item–padding–x;
clear: both;
font–weight: $font–weight–normal;
color: $dropdown–link–color;
text–align: inherit; // For `<button>`s
white–space: nowrap;
background: none; // For `<button>`s
border: 0; // For `<button>`s
}
这样的注解是有用的,它们能告诉我们,那些特定的属性是为覆盖<button>样式而写的。这样的注解是有用的,因为有时候标识符的意图不是那么显而易见的。
但此时也需要问一个问题:有甚么办法能让标识符自表明呢?需要可以考虑将那些特定的属性移到第二个选择器中,专门为那些按钮设置的选择器。
.dropdown–item {
display: block;
padding: $dropdown–item–padding–y $dropdown–item–padding–x;
clear: both;
font–weight: $font–weight–normal;
color: $dropdown–link–color;
white–space: nowrap;
}
button.dropdown–item {
width: 100%;
text–align: inherit;
background: none;
border: 0;
}
这样就非常清晰且易于理解,但副促进作用是:专门增加了一个特殊的选择器。
而相反,我认为这种形式非常利于使用mixin混入模式。重构为一个函数,该函数能在其他地方定义,并且让标识符更清晰。考虑如下表所示标识符:
.dropdown–item {
@include remove–button–styles;
display: block;
width: 100%;
padding: $dropdown–item–padding–y $dropdown–item–padding–x;
clear:both;
font–weight: $font–weight–normal;
color: $dropdown–link–color;
white–space: nowrap;
}
这段标识符没用任何注解,但其功用很清晰,因为它使用的公用函数在其他模块也能用到。我将width:100%保留下来而不是移到函数中,因为若将函数混和标识符时,width:100%可能会引起一些其他问题。
在我开始发现“标识符异味(Code Smell)”之前,一开始.dropdown-item标识符有十行,我非常喜欢用mixin,mixin是一个能极大减少标识符行数的好东西,它能让我们加速的知道标识符的大致用途。
虽然使用函数重构标识符并不是都这样有效,但尽量多用。
好:注解难懂的补丁性的标识符
我对注解也不是总那么苛刻的,比如我就很难找到下面的注解的问题,若你曾看过normalize.css的源码,你一定会注意到它满满的注解,不得不说,真是“极好的”注释。
欣赏一番:
/**
* 1\. Add the correct box sizing in Firefox.
* FF下正常的盒子模型
* 2\. Show the overflow in Edge and IE.
* 在Edge和IE下overflow为visble
*/
hr {
box–sizing: content–box; /* 1 */
height: 0; /* 1 */
overflow: visible; /* 2 */
}
若没那些注解,你永远不知道为何这样写。修复特定浏览器bug的标识符往往是晦涩难懂的,常常会被当做无用标识符删掉。
由于Normalize库的目标是提供一个全然一致样式环境,因此需要很多这样的注解。选择器都是类型和属性选择器,没任何class名,同时由于不是可命名的class名,因此自文档非常困难。
如下表所示为另一段Bootstrap的注解:
/* Chrome (OSX) fix for https://github.com/twbs/bootstrap/issues/11245 */
select {
background: #fff !important;
}
一个Github链接,非常有用。即使不
当然,不是每个打补丁的标识符都要这样注解,但若bug不是那么容易发现,而且与浏览器怪癖有关,那么还是这样注解吧。
好:指令式注解
一些工具如KSS , 会在CSS文件中创建一些样式规范。如下表所示:
/*
Alerts
An alert box requires a contextual class to specify its importance.
一个警告信息框需要与语境有关的的类来指定其重要性
Markup:
<div>
Take note of this important alert message.
</div>
alert-success – Something good or successful 好的或成功的
alert-info – Something worth noting, but not super important 不那么重要的
alert-warning – Something to note, may require attention 需要被提示并记录,需要引起注意的
alert-danger – Something important. Usually signifies an error. 非常重要的,常用于错误
Styleguide Alerts
*/
这不仅仅是注解,这是规范,它能被KSS解析并用于生成HTML。这已经算是项目文档的一部分了,而且不得不说,这比手动创建一个分离的HTML文件要好很多,因为其在同一个文件内且始终与标识符相匹配。
另外一种指令式注解为许可信息,当使用第三方库并在注解中注明许可信息时,一般都需要包含。
而我贴出Robert Martin关于注解不然时,似乎应该解释一下,但我没那么做。因为我认为这是一句容易理解不然,若你还在标识符中到处写注解,那么请先思索是否合理。
觉得本文对你有帮助?请分享给更多人
高度关注「前端大全」,提升前端技能