起步
最近看到关于css命名的文章Naming CSS Stuff Is Really Hard,于是就来学习一下,顺便练习一下英语阅读能力。
PS: 翻译中的「」
部分表达我的个人解读。()
是原文。
以下为正文:
Naming CSS Stuff Is Really Hard
通过选择不太可能改变的类名(Class Names)可以减少明天的重构工作。Ethan分享了三种的命名选择,来帮助我们减缓下一个明天设计的变化所带来的问题。
这不是一个关于CSS架构的帖子,也不是关于CSS命名约定的帖子。相反,我们来谈谈我们用来连接样式与元素及与它们相关的东西。
十之八九,开发者都会同意:命名是CSS中最困难的部分。这是因为我们无法预测未来。一个class name
今天可能会有完美的感觉,但当设计修改了,第二天就会让人觉得变了味。然后我们又得重新组织标记及样式,重新让它们赋予意义。呸!
那么我们该怎么办?——选择不太容易改变的名称。
我们通常可以将确定的类名(class name
)分为三类:
- 功能性的Class(Functional Class Names)
- 基于内容的Class(Content-based Class Names)
- 表现型(Presentational Class Names)
一个确定类别的类名通常倾向于可维护的特征。
如果我们使用以上的分类去定义一个类名的类别,我们可以做出更明智的决定,使我们的CSS更具弹性。
Functional Class Names
<button class="positive-button">Send Message</button>
使用positive-button
「正面按钮」,important-text
「“重要”文本」, selected-tab
「选择标签」命名,这类元素的样式基于它的功能或者元素的意义。这类元素的特点是其样式本身、应用样式(style)的原因以及命名(class name)之间有很强的联系「例如栗子中的正面按钮,其样式与功能有很深的联系,因此使用功能型命名」。
因为样式与元素之间存在紧密的联系,这些风格通常不能随意更改。如果你需要更改它的样式,通常是希望更改每个元素实例的样式「这类元素的命名,一般用于页面中的一类功能,例如某个功能按钮,当一个样式更改,会影响所有使用这个命名的元素」。如果设计师正在考虑修改positive-button
按钮「的样式」,而不是“设置菜单”中的Add User
按钮,你将处于一个开心、可维护的位置。因为它是一个系统「一类功能」,而不是页面。
功能型的命名很好,这可能就是你想要的命名方式。需要注意的是,它并不总是行得通。
设计并不总是有逻辑的,对于按钮(button)而言,我们总能使用功能型的命名。大多时候,它们的功能与样式密切相关。但我们写的其他99%的样式都不简单,有时我们需要插入一段看起来不错的阴影,有时icon需要悬停增长的效果让它看起来可爱,有时文本需要橙色,emmm,它就是需要橙色。因此使用功能型命名,并不算得上表达网站中每一处视觉效果的正当理由。
如同站在十字路口一样,我们有时并不能想到一个很好的功能型的命名,我们仍可以根据其内容,或基于其表达的意义(presentation)命名该元素,这两者对可维护性有不同的影响。
Content-Based Class Names
<button class="submit-button">Send Message</button>
基于内容的类名描述的是它包含的内容,例如:submit-button
「提交按钮」, intro-text
「介绍文本」,profile-photo
「个人资料图片」。
这些类名让人感觉很干净。它们有助于你在内容(HTML)与样式(style)之间保持清晰的隔离。理论上,这能不去触碰你的HTML,就够使你重新设计网站的样式,如CSS Zen Garden「网站设计领域最著名的网站之一,现在已过时」。这像是一个巨大的perk「不清楚词表达的是什么意思」,对吧?
现在,我想请你坐下,并且向自己提出一个疑问:“这对我有什么好处?”
我从未被要求不碰HTML的情况下重新设计网页,你同样也不会。当然,一些HTML会被后端集成而锁定无法更改。但一旦你失去对HTML的控制,你可能需要使用一些不太理想的CSS Hack
来改变设计。请记住,CSS禅意花园更像一个CSS优秀样例,而不是一个可维护的CSS的例子。当你不需要时,请不要为了纯CSS的重新设计而优化它。「这里主要指内容型CSS命名下,CSS与HTML隔离的优缺点」
如果你开发的是一个小网页,内容型类名会工作的很好。随着你的站点的发展,它们将越来越不合适。它们并不适合样式的复用。如果你的login-button
、submit-button
长得一样怎么办?它们在CSS架构中应该代表什么?为了防止样式块「应该是指同一个样式的选择器」重复,你不得不使用逗号分隔选择器,或者使用预处理器来提供一些拓展性。在大型项目中,这两个选择都难以适用和组织。
如果只有更好的方式来重复使用同一块样式...
Presentational Class Names
<button class="green-button">Send Message</button>
演示型类名描述的是元素看起来像什么,比如green-button
、big-text
、squiggle-border
。它描述的就是元素的样式。
这类代码有助于重构。它们不在乎用于产品的标题、用户名或者页面标题。它们就是会使文字变大(text big)或者变粗(bold)。这种命名带来的好处也包括优雅的缩放。当你开发新组件时,你可以重复使用它们。你也不需要担心,写新样式时需要融入旧样式架构的问题,因为你不需要写新的样式。
演示型类名是非常描述性的。当使用round-image
而不是profile-photo
时,开发者检查代码,可以更容易的知道元素长什么样。
可以说,演示类提出了一些可维护性的问题。因为它模糊了表现和标记(markup)的界限,许多设计的变更会迫使HTML部分需要更改。如果你预计这会成为你项目的一个问题,请谨慎使用。
但,这不语义化!!
演示类是一个糟糕的rap「说唱来表示它不够语义化」,许多人因为“不语义化”而避免这种命名。然而,这是一个神话,它是busted by Nicolas Gallagher,区分“Semantic HTML”和“Semantic Class”非常重要。Nicolas说的好:
写语义化HTML这个原则是现代专业前端开发的基础之一,大多数语义与现有的内容或者预期的内容相关。
然而,并不是所有的语义必须与内容来源有关。Class的命名不能非语义化(unsemantic),无论使用什么样的名字,它们都有意义或者目的。Class名称的语义可能与HTML元素不同。
当我写这篇文章时,非语义化(unsemantic)这个单词下面有报错的红色横线。非语义化名称不是一个东西。每一个类名都有一些含义。当你构建命名时,不要陷入构建“语义最合适”的类名的情景。请记住,类名只适用于开发者,而不是用户。考虑类名时,请尽可能的向与你同行的开发者提供更多的信息。
结尾
功能型的命名方式通常是你最好的选择。当你可以使用它时,就去用它。如果你不能构建一个非常健壮的的功能名称,请考虑项目的性质及未来将如何发展。经验法则:基于内容的命名对小站点更合适;演示型命名更适合大站点。
开发者会弄清楚这种东西。没有任何人希望项目变得不可维护,但每个人对于如何防止这这事情发生的理解是不同的,特别是类名。思考类名的性质对于你正在使用和质疑项目是否符合目标是有帮助的。
个人解读
全文主要讲的CSS命名方式的三种倾向及其影响。英语语义的表达与中文有非常大的不同,个人的英语水平有限,对于文章中三种分类的表达,有下面粗浅的看法:
Functional Class Names
是一种关于作用(功能、模式)的命名类型。它基于网页设计中的功能模式。在重复的结构或相同功能的地方,你可以反复它。这种命名类型更具有复用性。
Content-Based Class Names
是一种内容型的命名类别,它基于内容本身命名。内容绑定了这个样式,你可以通过重新设计它的样式来更改它的表现,以此达到CSS与HTML区分的效果(文章中也是这样说的)。但这样在开发中就会遇到不可复用、一个CSS类与HTML绑定的情况。实际上这样做,内容与Class命名将有更强的联系。当站点复杂程度提升时,这种命名方式就会变得不利于维护,尤其是在一个开发团队中。
Presentational Class Names
,这种命名类型基于元素的外表,即它长什么样,比如blue-button
,green-tab
。直观的表达样式,有助于开发者理解样式与代码间的关系,便于开发者维护。
总的来说,我们常用的Bootstrap、Element UI、AntUI、iview等等UI库是文中类型的合集,它们将特定功能、内容、外貌组成不同的组件,通过不同类型的命名来区分,最终达到组件UI的效果。
对于项目开发,多思考类名的类型,理解不同业务场景下的命名类型,有助于我们更好的在开发中构建健壮的项目。合适的命名通常会有三种原则:
- 便于开发者理解元素的样式。
- 同一个项目中可复用。
- 便于后续开发的维护。
另一篇文章中提到,对于class name而言,它的语义化可以与html不同,即与内容并不完全相关,而是以项目结构为主。比如:
/* Utility */
.u-utilityName {}
/* Component */
.ComponentName {}
/* Component modifier */
.ComponentName--modifierName {}
/* Component descendant */
.ComponentName-descendant {}
/* Component descendant modifier */
.ComponentName-descendant--modifierName {}
/* Component state (scoped to component) */
.ComponentName.is-stateOfComponent {}
在现在的大部分开发中,我们大多都是这么做的。这样更便于项目的维护,尤其是在项目越发复杂的今天。
另外,我们还可以通过类名提供JS钩子,以此减少更改组件结构、或者主题的情况:
<a href="/login" class="btn btn-primary js-login"></a>
Reference:
Naming CSS Stuff Is Really Hard
About HTML semantics and front-end architecture