CSS 命名空间

1,521 阅读6分钟

为什么需要命名空间

我们之所以需要命名空间,一方面是为了扩展,最重要的原因是在看代码的时候,能够简单快速的了解各个函数,模块是做什么的。我认为这是命名空间需要解决的问题,也就是说变量冲突能够在隔一段时间或者别人接你的代码的时候能够快速上手,这个我觉得是比较重要的。

BEM(block element modifier)

BEM 把样式名分为 3 个级别,分别是:

  • Block:对应模块名,如 Dialog
  • Element:对应模块中的节点名 Confirm Button
  • Modifier:对应节点相关的状态,如 disabled、highlight

BEM 最终得到的 class 名为 dialog__confirm-button--highlight。使用双符号 __ 和 -- 是为了和区块内单词间的分隔符区分开来。

BEM这种命名方式非常的清晰,也非常直观的能帮助我们了解这个元素到底具体应用了些什么样式,非常直观。 但是弊端我觉的也是很明显的 团队之间使用这种命名规范的时候,水平的高低直接决定使用的效果,比如什么时候ELement叫item, 如果两个menu非常相近的情况下(可能只是位置上变动),是不是又需要一个命名Modifier去修饰它,本来使用这种命名方式的成本也不小(命名太长了),这些因素导致了对开发团队的要求太高,不利于推广

element-ui 组件命名

为什么BEM不能满足我们

举个例子

<div class="info"> 
    <a href="#">link</a>
    <button class="button">详情</button>
</div>

button的颜色从red变成blue 同时按钮距离链接10px css实现

  1. .info .button 添加margin 和background-color
  2. button--modifier添加margin 和 background-color
  3. .info .button 添加margin, button--modifier添加background-color
  4. .info a添加margin , .info .button 添加mbackground-color
  5. .info a添加margin ,button--modifier添加background-color

即便用了BEM也有很多情况,这就是之所以引入命名空间。它可以帮助你创建一个结构来控制CSS属性的写入。 如果您遵循惯例,您将能够无惧副作用地编写CSS

把上面的代码转换成一个带有命名空间的代码。HTML将完全相同(只加了少数的class前缀)。 在这个例子中要特别注意.o和.c前缀:

<div class="c-info"> 
    <a href="#">link</a>
    <button class="o-button">详情</button>
</div>

.o-和.c-是什么意思呢?从这个代码来看,我知道如果我想,我可以改变.o-button的颜色,但我不应该添加任何边距到.o-button

对象独立于上下文

当我说对象是上下文独立的时候,我的意思是他们不知道在哪里会被使用。 你可以选择任何的对象,并把它放在你喜欢的地方,而且并不会破坏你的网站的结构。

这也意味着对象不应该更改外部任何结构。 因此,对象块不能包含任何这些属性/值:

  • absolute 和 fixed 定位。
  • margin
  • padding (除非你用了background-color。 在这种情况下,它不会中断对象外部的对齐)。
  • float. 等等… 既然你知道对象需要与上下文无关,你马上知道我们站点范围的导航示例中的.button不能包含任何边距。

对象使用总结

对象(.o-)是一个网站的最小的构建块。

对象物们都有着以下的属性:

  • 对象使用.o-前缀
  • 它们的里面不能包含其他对象或组件
  • 它们之于上下文是独立的
  • 某些对象可以在有意义的情况下忽略.o-前缀

组件的总结

  • 组件(.c-)是您可以在整个站点中使用的更大的构建块

组件有着以下属性:

  • 组件使用'.c-'前缀
  • 组件可以包含其他对象和组件。
  • 组件是上下文感知的

“.js”——JavaScript的钩子

Javascript 钩子(.js)表示对象/组件是否需要JavaScript。

使用JavaScript命名空间的好处是可以将JS功能与样式分开,这使得它们更易于维护。

例如,您刚刚看到.jsCountdown类就可以立即知道,.o-countdown需要JavaScript才能正常工作。 如果将来有需要将o-countdown更改为c-countdown,我也不必担心破坏任何JS功能。

“.is-/.has-” ——状态类

状态类表示对象/组件的当前状态。当应用状态类时,您可以立即知道对象/组件是否具有下拉(.has-dropdown)或当前处于打开状态(.is-open)。

“.t”或“.s”——排版类(Typography)

在排版中最好的做法是在网页上只使用少数样式(大小,字体等)

  • .t1 - 最大的字体大小。
  • .t2 - 第二大字体大小。
  • .t3 - 第三大字体大小。
  • .s1 - 第一字体大小较小的基本字体大小。
  • .s2 - 第二字体大小较小的基本字体大小。

能够一目了然地告诉元素的大小 排版类是对象的子集。您应该像排列对象那样将相同的一套规则应用于排版类。 这意味着你不应该在排版类中添加margin或padding。而这些margin或padding应该直接添加到组件。

“.u-” ——实用类(Utility)

实用类是用来表现样式的一个非常好的辅助类。它们做得很好,并且其优先级高超过了其他样式。 因此,它们通常只包含一个属性,并且包含!important声明。

汇总

  • 类必须尽量少地添加避免HTML膨胀
  • 我必须立即知道组件是否使用JavaScript
  • 我必须立即知道是否可以安全地编辑一个类而不会影响其他任何其他CSS
  • 我必须立即知道每个class是适合于什么,以防止大脑过载
  • .l-: 布局(layouts)
  • .o-: 对象(objects)
  • .c-: 组件(components)
  • .js: js的钩子(JavaScript hooks)
  • .is-|.has-: 状态类(state classes)
  • .t1|.s1: 排版大小(typography sizes)
  • .u-: 实用类(utility classes)

每个命名空间都有一个功能,可以在整个事物的宏伟计划中进行,进一步加强了样式表中的层次结构

总结

命名没有什么标准答案,但是我css命名空间的制定是非常考验一个工程师的设计能力的事情,只要找到适合自己团队的方式,能够在此基础上快速扩展,那就非常ok了,当然团队还是的需要找到一个大家都能比较通用的解决方案,这样在开发中,才能够更加快速,高效的工作。

参考资料: