构建稳固的、可升缩的CSS框架的八大原则

& 这个符号可以在所有相关的css预编辑器中使用 — (SASS, PostCSS, LESS 和 Stylus)。下面所展示的便是上面的代码在SASS中的编译结果:

.myapp-Header {  background: black;  color: white;}.myapp-Header-link {  color: blue;}.myapp-Header-signup {  border: 1px solid gray;}

所有经常使用的模式在该种定义下都能很好地被编译出来,例如: 为不同状态下的组件设置不同的样式( Modifier in BEM terms):

.myapp-Header {  &-signup {    display: block;  }  &-isScrolledDown &-signup {    display: none;  }}

编译结果:

.myapp-Header-signup {  display: block;}.myapp-Header-isScrolledDown .myapp-Header-signup {  display: none;}

即使是对于媒体查询的设置也能很方便的进行,只要你使用的预编辑器支持“冒泡”这个功能。(SASS, LESS, PostCSS and Stylus都支持):

.myapp-Header {  &-signup {    display: block;    @media (max-width: 500px) {      display: none;    }  }}

编译结果:

.myapp-Header-signup {  display: block;}@media (max-width: 500px) {  .myapp-Header-signup {    display: none;  }}

上面所提到的方法使得我们不用一遍遍地编写重用的代码就能使用长但却独一无二的类名。而这种便捷性是必须要考虑到的。因为一旦没有了便捷性,我们便会“偷工减料”。

在JS文件里快速命名

虽然这部分是关于样式设置的便捷性的,但是样式并不会独立存在。也就是说,JS文件里同样需要以相同的命名方式快速地完成命名工作。

“无耻”的做个宣传,我已经编写出了一个完全不依赖任何JS库的简单方法来实现这一功能,即: css-ns。当其与框架层一同使用时 ( 如:React),会在一个指定的文件中 强行 加上特定的命名空间,如:

// Create a namespace-bound local copy of React:var { React } = require('./config/css-ns')('Header');// Create some elements:<div className="signup">  <div className="intro">...</div>  <div className="link">...</div></div>

渲染而成的DOM树为:

<div class="myapp-Header-signup">  <div class="myapp-Header-intro">...</div>  <div class="myapp-Header-link">...</div></div>

这很便捷,而且该JS文件可以直接在本地使用。哎,我又再一次离题了。重新回到CSS上吧!

6. 防止泄漏组件内的样式

还记得我说过每个类名前面加上组件的名称空间是一个“非常有效”的沙盒风格吗?还记得我说过这种方法有“注意事项”吗?

看一下下面的样式:

.myapp-Header {  a {    color: blue;  }}

下面是组件的等级分布图:

+-------------------------+| Header                  ||                         || [home] [blog] [kittens] | <-- these are <a> elements+-------------------------+

我们很酷,对吗??只有 Header里的元素有blued样式,这是由我们生成的规则决定的:

.myapp-Header a { color: blue; }

但是如果布局变成了下面的结构:

+-----------------------------------------+| Header                    +-----------+ ||                           | LoginForm | ||                           |           | || [home] [blog] [kittens]   | [info]    | | <-- these are <a> elements|                           +-----------+ |+-----------------------------------------+

.myapp-Header a 这个选择规则同样适配LoginForm里的元素, and we've blown our style isolation. 这也说明了一个事实:将所有的样式放在一个命名空间下确实是一个将其与其他组件相区分的有效方法,但是却不能有效地区分其内部元素的样式.

可以用以下两种方法改善这个问题:

  1. 决不在样式文件中使用元素名称。如果Header组件里的所有元素都不相同,那么我们也不用去处理这个问题。但是为了更好地建立语义标注,有时会在不同的地方使用多个相同的元素,而且你也不想用多余的类名去区分他们,那么在这种情况下,我们采用第二种方法。
  2. 在命名空间中将元素名与选择器“>”配合使用。 应用该种方法后, 我们的样式重写为:

    .myapp-Header {> a {color: blue;}}

    当然,因为此时的选择器为.myapp-Header > a,这会使得“样式隔离”对于组件树中深层次的元素同样奏效。如果这不能让你信服,我们可以看一下下边这个同样凑效的例子: