161010、在大型项目中组织CSS

时间:2022-01-19 19:57:28

编写CSS容易。 
编写可维护的CSS难。

这句话你之前可能听过100次了。 
原因是CSS中的一切都默认为全局的。如果你是一个C程序员你就知道全局变量不好。如果你是任何一种程序员,你都知道隔离和可组合的模块是构建可维护系统的关键。

为了试图帮助人们构建可维护的CSS,已经有很多CSS指南了:SMACSSOOCSSBEMITCSSACSSCCSS,Atomic DesignMaintanable CSSrscss, 并且可能还有 更多.

那么,CSS的问题是什么?

span {

 font-size: 11px;

}

.header-right {

 font-size: 22px;

 text-align: right;

}

用一个如上的CSS定义,样式立马变成全局的,它会影响所有应用样式的页面。没有封装。没有隔离的模块。

在一个标准的编程语言里,你只会为了要实现的特定功能引入一些模块,例如:

# Python modules

import requests

from Flask import url_for

// Node modules

var express = require(‘express’)

这样,你准确地知道什么会影响你的代码,并且只有你显式引入的内容才会影响到你当前正在实现的功能。

而在CSS中是反过来的。我每写一行CSS代码,可能会影响到项目里的所有部分,并且会无意间改变其他页面的外观。我的样式不仅仅是泄露;它们蜂拥而出,遍布应用程序的每个角落。

对基本的样式设定如印刷格式,只是设定输入字段的样式,或者本来就是全局的样式来说,这是可以理解的,也是合乎情理的。基本上HTML和CSS就是为此而生的。这些工具是为出版物制作的。为了理解这些语言背后的思想,我经常设想在给书排版:你不会想让每一页看起来都不一样——是的,你想要简单一致的样式贯穿整本书,没有太多垃圾。这就是为什么像s之类的标签是合理的,并且样式是全局的,会一直存在。

然而,世界变了,web也变了。我们不再制作网页——我们构建web应用程序。HTML和CSS为之建立的出版物隐喻,不再适用于当今建立在web之上的大部分事物。

这确实需要一种 指定样式的新方式,也许还要一种构建web的新方式。但是就目前来说,我们还无法摆脱CSS和HTML,这意味着我们不得不用一种产出可管理和可维护的应用程序的方式小心地使用这些工具。

Peergrade.io 处理CSS的方式

法则一:(给类名)加上前缀

在Peergrade.io我们在所有类名中用了前缀 .pg 。在CSS代码库里不使用前缀是自找麻烦。原因就是不加前缀的类名最终将会跟引入的样式冲突。假设你需要一个datepicker ——你肯定不愿意从头开发一个(至少我不愿意),因此你引入了一个。现在你的样式里到处都是.prev.next, 和 .separator这样的类名,可能会跟你自己的类名冲突——如果你不加前缀的话。

很长一段时间 Font Awesome没有在他们的类名上加前缀,这意味着你经常跟他们的.icon-* 类名发生冲突(他们现在用了前缀 .fa)。我们也难过地发现 Bootstrap 也没有选择加前缀——但我们依然 ❤ 你, Mark Otto

法则二:避免使用CSS选择器嵌套

在Peergrade.io我们使用 Sass。使用 Sass 你很快进入一种Sass结构跟HTML结构相匹配的模式,例如:

#user-profile-page

 .profile-description

   h3

   ul

     li

       a

这么做之后你会发现,尽管感觉不错,但它非常脆弱。在你写它的时候你可能认为在.profile-description里只会有一个列表,但一两个月后你发现不得不需要另外一个列表,页面结构很快超出你的设想。

并且,像这样的样式定义会应用到父元素内部的任何元素上——而不仅仅是你写在Sass里的那个层级。

对CSS选择器嵌套你所做的是用 微妙 和 脆弱的方式绑定CSS和HTML结构。

法则三:采用BEM命名来开发组件

在构建可隔离组件时,尽可能采用BEM命名方案给类命名。我们没有遵循完整的BEM指南——只是命名方案,这就是说类名应该是这种形式:

.block__element--modifier

为此我们这样组织我们的 Sass:

.pg-deadline

 &__date

   // becomes `.pg-deadline__date`

   color: $color-gray

 &__header

   // becomes `.pg-deadline__header`

   font-weight: 700

   &--highlight

     // becomes `.pg-deadline__header--highlight`

     color: $color-green

这里你看到的是我们用Sass嵌套为我们创建BEM类名。有点反直觉的是,这会产生完全扁平的css结构——没有嵌套——只有顶层的类名定义。

作为法则二的一个例外,我们允许 .block–modifier 形式的类名。

.pg-deadline--editable

 .pg-deadline__header

   background-color: $color-blue

 .pg-deadline__date

   color: $color-black

在这个特殊的例子中,我们允许 1层CSS选择器嵌套。这就允许我们只要指定区块的修饰符——也就是正在编辑的内容—— 不用在区块内的所有子元素上重复修饰符(BEM中的E)。

为了更好地理解类似BEM的命名方式,前往查看Harry Roberts的CSS指南的类BEM命名部分。(需要提到的是,我们发现Harry实际上建立了一套跟我们类似的命名方案。)

展望

似乎还没有人真正找到处理CSS的最佳方式,看着Hack News上精选的这篇文章,我对CSS的现状多少有点失望,本来我们可以做得更好。

结论就是:我们相信已经找到了CSS的可持续基础——当然还有改进的空间。这个计划就是经常对照检查我们的指南,看看事情是不是朝我们预期的方向发展,并且在必要的时候修订。

END

掘金是一个高质量的技术社区,从 ECMAScript 6 到 Vue.js,网站性能优化到开源类库,让你不错过 Web 开发的每一个技术干货。