本文主要是探讨传统项目中的css命名,vue、react等单页应用都可以使用css-module来解决这个问题

作为一名初级前端,免不了要切图(写css、html静态部分),写css最头痛的就是给class命名了,词汇有限,本人又比较懒,想类名比布局还费劲。在网上找了一通,css规范到是有比较统一的,接受度较高的。但css命名似乎没有什么比较完美的方案。

简洁法

张鑫旭大神的简洁法是这样的:

.fr {
    float: left;
}

.tc {
    text-align: center;
}

.pb8 {
    padding-bottom: 8px;
}
<div class="fr tc pb8"></div>

简洁法重用率高,性能好,但是这么一堆class,有点写行内式样的感觉了,维护起来太难受了。毕竟这是张鑫旭七年前的文章。

BEM命名法

BEM的意思就是块(block)、元素(element)、修饰符(modifier),是由Yandex团队提出的一种前端命名方法论。这种巧妙的命名方法让你的CSS类对其他开发者来说更加透明而且更有意义。BEM命名约定更加严格,而且包含更多的信息,它们用于一个团队开发一个耗时的大项目。 ————摘自大漠老师BEM科普

BEM应该算是比较科学比较系统的命名法了,每个class都BEM来一套,自然不会混乱。但是这冗长的类名写起来,真让人手软。虽然用scss的&选择器可以省不少事,不过html里的冗长类名还是免不了,pug等html模板也救不了我们啊。

于是我在想有没有一种既科学又简洁的css命名法呢,于是我自创了一种命名空间法,在自己项目里用的倒挺开心。但此法没有经过大型项目的考验,希望大神们来探讨一下可行性。

命名空间法

基本思想

此法配合scss使用更佳哦,思想就是在最外层使用独特的模块命名,在内层使用简单的类名,禁止在最外层使用简单的类名,不同的模块之中,可以任意使用简单的类名,并不影响其他模块。

举个例子:

.m-header {
    .left {
        background: red;
        height: 10px;
    }

    .right {
        background: yellow;
        height: 10px;
    }
}

.m-body {
    .left {
        background: blue;
        height: 10px;
    }

    .right {
        background: green;
        height: 10px;
    }
}
<div class="m-header">
    <div class="left"></div>
    <div class="right"></div>
</div>

<div class="m-body">
    <div class="left"></div>
    <div class="right"></div>
</div>

结果是这样的:
html

不了解scss的同学可以看一下编译后的css:

.m-header .left {
  background: red;
  height: 10px; }
.m-header .right {
  background: yellow;
  height: 10px; }

.m-body .left {
  background: blue;
  height: 10px; }
.m-body .right {
  background: green;
  height: 10px; }

两个模块(m-header和m-body,模块推荐以m-为前缀)中的.left和.right互不影响,只要我们在最外层定义一个独特的类名,如同命名空间,并且不在最外层使用简单类名,防止冲突。那么我们就可以再模块内部随意使用各种类名,当然下个模块内可以再用一次,妈妈再也不担心我词汇量不足了,想不出名字了。

.top, .bottom, .left, .right上上下下左右左右baba一套又一套。为了规范推荐使用更加语义化的类名,当然不必带上长长的前缀。

公用式样

一个项目里可能会有很多公共式样,其实只要我们遵循一点规范便不会发生冲突。比如公共式样我们统一带上'p-'前缀。其它地方你就别用'p-'做前缀了。scss里的mixin、function、$variable我们也可以用起来,提高效率。

.p-btn {
    font-size: 14px;
}

.p-bg-green {
    background: green;
}

 嵌套过深的问题

很多css规范里都规定嵌套不能超过四层,下面这个例子里我们已经嵌套6层了。在scss里我们不能直接使用@at-root这会将简单类名暴露到最外层。使用&也不能避免嵌套过深。

这时我们需要使用@at-root 后面写上模块名空格即可防止嵌套过深,并避免式样污染了。嵌套特别深的情况下推荐启用子模块。(这里可能存在漏洞,不知道大神们有没有更优雅的方案)

.m-header {
    .a {
        background: #000;
        .b {
            background: #111;
            .c {
                background: #222;
                @at-root .m-header .d {
                    background: #333;
                    .e {
                        background: #444;
                    }
                }
            }
        }
    }
}

编译成css:

.m-header .a {
    background: #000;
}

.m-header .a .b {
    background: #111;
}

.m-header .a .b .c {
    background: #222;
}

.m-header .d {
    background: #333;
}

.m-header .d .e {
    background: #444;
}

使用子代选择器让命名更随意

如果你不用兼容老掉牙的ie6,对于一些只在子代中生效的式样(大多如此),带上子代选择器吧。多敲一个>,优点是css渲染效率更高,命名可以更佳随意,你甚至可以这样,虽然不推荐。

.m-header {
    > .a {
        height: 40px;
        background: red;
        > .a {
            height: 20px;
            background: green;
        }
    }
}
<div class="m-header">
    <div class="a">1
        <div class="a">2</div>
    </div>
</div>

式样并没有冲突:
html2

总结一下命名空间法规范

  1. 最外层css模块m-为前缀,并且类名独一无二。
  2. 模块内元素式样通过后代或子代选择器约束,只作用与此模块,使用简洁的语义化命名。
  3. 公共式样使用p-为前缀。
  4. 禁止在最外层使用简单的类名,可增加特定前缀,防止污染模块内式样。

此方法与很多编程语言的命名空间有着异曲同工之妙,大家应该看到了私有变量和全局变量的味道。在下经验尚浅,不知道此法有没有大的漏洞,欢迎大家理性讨论,指出问题或加以完善。

补充

自己用了一段时间,如果不是非常复杂的项目(如评论区大神所说的动态css和动态dom)问题不大。有几点感觉需要改进一下:
第一,为了避免嵌套过深和便于复用维护,模块内部不要使用嵌套了,用scss写到第二级就好
第二,父子选择器还是不要用了,因为dom父子关系经常会变动,模块内部css命名推荐用唯一的。

这种方法的确有很多人在用,比如网易的CSS规范 - 命名规则,我发誓之前没有看过 :)逃了


无风
670 声望63 粉丝