系列文章
目录
- 遇到的问题
- 解决的办法
- Block, element, modifier
- Sass 和 BEM
- 总结
遇到的问题
我们知道 CSS 只有一个作用域,无论你通过什么选择器去操作样式,一旦你声明一个选择器,它就是全局的,如果项目复杂,维护人必须小心意义,因为你一不小心可能就会影响到其他元素,代码的维护性很差,而且 CSS 代码的可读性也不行。
浏览器曾短暂通过 scope 字段支持 CSS 作用域,
:scope
伪类就是曾经遗留的证据。
但是项目中我们总是希望编写可读性强且易于维护的 CSS 代码,我们应该寻找一种方法来解决它。
PS:上面这个讨论前置条件是传统网页开发,因为现在的 CSS 模块方案,通过将样式范围限定到组件模板作为标准,在很大程度上解决了这个问题。这意味着您无需担心一个组件中的类会影响另一个组件的样式——即使您使用相同的类名。
解决的办法
首先我们要意识到无论多复杂的网站,它都是有结构的,我们都可以对他进行分解,比如:
我们把网站分为 head、body、foot 三部分,同时在 head 里面继续划分 logo、menu。
其实这种分解很像语义化的 HTML 标签。
好了,我们借助网站的结构,进行分解,找到了避免样式代码混乱的方法。
现在只要耐心的细分就能理清网站的结构,那我们怎么让它体现在代码上呢——BEM。
Block, element, modifier
根据上面的思想,由 Yandex 团队提出的一种 CSS 命名方法论 BEM。
首先 BEM 是一个分层系统,它把我们的网站分为三层,这三层正好对应着 BEM 三个英文单词的简写 block, element, modifier,分为为 块层、元素层、修饰符层。
让我们来看看 BEM 构建的网页样式
Block:您希望将样式范围限定到的 HTML 块
.block {
}
Element:该块内的任何元素,名称与您的块名称隔开
.block__elementOne {
}
.block__elementTwo {
}
Modifier:用于修改现有元素样式的标志,无需创建单独的 CSS 类
.block__elementOne--modifier {
}
下面是 HTML 结构:
<section class="block">
<p class="block__elementOne">This is an element inside a block.</p>
<p class="block__elementOne block__elementOne--modifier">This is an element inside a block, with a modifier.</p>
</section>
你会发现我们的类名不知不觉暗合了 OOCSS 的思想。
把 BEM 体现到代码上,我们需要遵循三个原则:
- 使用
__
两个下划线将块名称与元素名称分开 - 使用
--
两个破折号分隔元素名称及其修饰符 - 一切样式都是一个类,不能嵌套。
根据这个原则,它的经典写法就是这样的:
block-name__element-name--modifier-name--modifier-value
我们可以翻译上面的案例,得出以下实战代码:
<section class="container">
<p class="container__paragraph">This is a paragraph inside a container.</p>
<p class="container__paragraph container__paragraph--bold">
This is a paragraph inside a container, with a modifier that adds bold styling.
</p>
</section>
Sass 和 BEM
使用 CSS 预处理器,我们都喜欢将嵌套作为范围定义样式,如果你想严格遵守 BEM 不准嵌套的原则,您可以以嵌套格式进行创作,使用@at-root
获得非嵌套的 CSS,:
.block {
@at-root #{&}__element { }
@at-root #{&}--modifier { }
}
得到:
.block {}
.block__element {}
.block--modifier {}
总结
我们回顾了传统网站,因为 CSS 只有一个作用域导致样式代码维护性和可读性极差,然后我们借助网站的结构对其分层,抽象总结出来了 BEM 这个方法论。
我想大多数人都觉得 BEM 的破折号和下划线看起来很奇怪,所以真是项目中很少有严格遵守 BEM 规范的 CSS 代码出现,往往大家都是接受 BEM 的核心思想然后通过短横线来连接这种命名规范,比如:head-input-search
。