这篇文章主要介绍了深入理解CSS中的属性模块,里面讲到了CSS中的类等重要进阶知识,需要的朋友可以参考下

更多 vs 更少 - 简单比较

神奇的是,虽然在标签里面放那么多类让我非常不爽,可是人们爱哈利,因为他太特么能说了。提倡的某些东西,比如说 OOCSS 和单一责任原则,从我自己创建的一系列日益复杂的网站来看,我可以说这确实值得对样式行为进行解耦,不过直到最近我才找到一种让我觉得满意的方式来实现它。

我原先有做过一个 BEM 的版本,它强调了独立高于重用 ‐ 每个新的块默认是没有样式继承的,允许组件独立开发并且可以避免打乱页面其它样式的风险。不过代价就是碎片化(fragmentation) ‐ 忽然你会发现你有了 10 种不同的样式链接,12 种不同的蓝色,18 种差别细小的按钮样式等。妮可?沙利文,OOCSS 的作者,去年在墨尔本做了一个超赞的演示,讲到了这个问题是有多普遍,以及怎么解决它。


对我来说,我觉得可以接受的解决方案是,深入 CSS 的预处理机能,从而取得 BEM 的独立性以及 OOCSS 的一致性。比如说,下面这样的:
 

CSS Code复制内容到剪贴板
  1. <a class='btn large rounded'>   
  2.     
  3. .btn { /* button styles */ }   
  4. .large { /* global large-type modifier */ }   
  5. .rounded { /* global rounded-border modifier */ }  

应该改成这样:
 

CSS Code复制内容到剪贴板
  1. <a class='btn btn--large btn--rounded'>   
  2.     
  3. .btn { /* button styles */ }   
  4. .btn--large {  @extend %large-type;}   
  5. .btn--rounded {  @extend %rounded-borders;}  

我成功终结了充满了占位符的文件,比如满眼都是那些_typography.scss 和 _brand.scss,这不但让我有能力控制碎片化,同时还能默认保持了样式的对每个新组件的独立性。所有的东西都挺好的,起码有那么一段时间是这样。

修饰符: M 是怎样破坏 BEM 的

只要你做关于 CSS 类的命名 & 维护方面的任何研究,你一定会要看到尼古拉斯.加拉格尔的杰作""。其中一部分特别吸引我,他称之为修饰符的 '单类模式' vs '多类模式'。简单的说,你的 HTML 会有两个版本,看起来像这样:
 
这通过两个备选的 CSS 模式实现:

 

CSS Code复制内容到剪贴板
  1. /* Single class */  
  2. .btn, .btn--large { /* base button styles */ }   
  3. .btn--large { /* large button styles */ }   
  4.     
  5. /* Multi class */  
  6. .btn { /* base button styles */ }   
  7. .btn--large { /* large button styles */ }  

这两个模式的差别在于 btn--large 是否只要它自己就足够了,还是说它需要依赖类 btn 。单类模式说”可以”,它看起来更简单而且可以避免有人忘记把 btn 包含进来的情况。而且它也不啰嗦,配合 SASS 的 @extend 方法,它对 CSS 来说不像一个负担,只不过它有一个致命伤。

上下文重写

我们假设你的所有按钮都有背景色,除了你顶部导航栏那些没有。在多类模式下,所有的按钮,大的小的,圆的方的,等等之类,都会包含类 btn,所以你可以这样写:
 

CSS Code复制内容到剪贴板
  1. header > nav > .btn { backgroundnone; }  

而在单类模式中,我们不知道哪种按钮会被重写,所以你只好这样:

 

CSS Code复制内容到剪贴板
  1. header > nav {  .btn, .btn--large, .btn--rounded { backgroundnone; }}  

很显然,这不理想 - 追加一个按钮变体也就意味着要检查所有地方的按钮样式重写以及添加一个新类。用属性前缀选择器 ^=,可以检查你的属性是否以特殊字符串开头,比如:
 

CSS Code复制内容到剪贴板
  1. <a class='btn--large'>   
  2.     
  3. [class^='btn'] { /* base button styles */ }   
  4. .btn--large { /* large button styles */ }   
  5. header > nav > [class^='btn'] { /* Overrides for all buttons */ }  

这实现了单类模式下的简单的上下文重写,不过它还是太弱了,不是一个可以托付的选择。最致命的是,如果另一个类在 btn--large 出现,而且前缀选择器还没匹配到它,那么之后的所有的都完蛋了。而且,它还没有显式的方法来指定多个变种,比如说 btn--large--rounded。

我很欣赏这种创造性的方式,不过还是死路一条。好吧,到这里我特么操蛋了,吐,直到忽然某天我灵光一闪。
 
为什么要用类?

不要在意我那么直接这种小问题,不过给我个理由先,为什么类是我们放样式信息的唯一位置?HTML生存守则如是说:

    3.2.5.7 类属性

    属性,如果要指定,就必须有一个用来标记该元素属于不同类的值,该值用一组空格分隔符来表示。

    而开发者在类属性中怎样使用该标记是没有任何限制的,但是鼓励开发者使用描述该内容的属性性质的表达,而不是描述该内容所期待呈现何种结果的表达。

所以对吧,我们用类来描述"内容的属性性质"是很有道理的,但是好像我们对类需求过度了吧。一个属性就包括了所有的东西,从巨大的 BEM-风格 命名,比如说 primary-nav__sub-nav--current 到像 u-textTruncate 或者 left 或者 clearfix,到 JavaScript 用的比如说 js-whatevs,然后我们花了巨多时间来解决命名冲突的问题,然后还希望他们有很好的可读性。

通过约定 & 习惯这是可控的,而且还有像文章前面说到的哈利的那种技术也挺有用的,不过,有一个事实是,我们所有的操作都是基于一个全局命名空间(global namespace)的,不管有多少规约都无法改变的事实。这让我们下面出场的 AM 就有那么一点不同了。

在我们正式开始讨论它之前,我们来复习一下 CSS 一个鲜为人知的特点。

欢迎 ~= 登场,神奇的选择器

从 IE7 开始,浏览器开始支持一种超厉害的 CSS 规则,叫做空格分隔属性选择器(space-separated attribute selector)。它可以匹配任何属性值,通过空格分隔,就像它们是类一样。下面两行的 CSS 是等价的:
 

CSS Code复制内容到剪贴板
  1. .dat-class { /* dem styles */ };   
  2. [class~='dat-class'] { /* dem styles */ };  

和 <div class='a b c'> 一样,它不在意 a,b 和 c 的顺序,也不在意是不是还有其它, ~= 选择器也不在意。不过 ~= 不限于类(class)属性,这就是这种全新技术的关键。

属性模块(Attribute Modules)

属性模块,或者叫 AM,它的核心是如何为你的样式定义命名空间。让我们从一个简单的例子开始,一个网格,首先用类的方式描述:
 

CSS Code复制内容到剪贴板
  1. <div class="row">   
  2.     <div class="column-12">Full</div>   
  3. </div>   
  4. <div class="row">   
  5.     <div class="column-4">Thirds</div>   
  6.     <div class="column-4">Thirds</div>