特别声明,本文来源于@RYAN YU的《Combining the Powers of SEM and BIO for Improving CSS》一文。
有人可能会说,CSS很简单,但是“容易”会导致代码混乱。在大家的眼里,使用像Sass或LESS这样的处理器会让事情变得更为简单。但事实上并不一定如此,如果你使用的不小心,你的CSS将变得更难处理,而不是更易处理。Sass?困难吗?Sass的嵌套就展示了这一点,使用不当,Sass的嵌套就是地狱。
如果你的Sass代码看起来像这样的,那么你肯定可以使用SEM和BIO来改进你的代码。接下来我就将向你介绍这方面的CSS技术。
在本文中,我将使用下面的代码示例来解释SEO和BIO是如何工作的,以及它们如何有助于增强CSS,如何更好的管理你的CSS。
通常,SEM关注的是CSS的高级技术,而BIO是帮助你编写更好的CSS,以实现SEM的实际技术。SEM和BIO的主要目的是更好地处理CSS的权重,这是你应该理解的CSS中最重要的概念之一。
首先,我们来聊聊SEM。
SEM
SEM是Scalable、Extensible和Maintainable三个单词的首字母的缩写。其意思是可伸缩的、可扩展的和可维护的意思。
尝试这样做肯定可以改进你的CSS代码,并帮助你构建更可靠的组件。让我们详细讨论一下这方面的细节。
可伸缩的(Scalable)
可伸缩的(或可重用的)组件意味着应该在不进行任何编码的情况下,在任意需要的地方使用外观相同的组件。
从上面的Codepen示例中,我们不难发现,在顶部(头部)中的搜索中的按钮(button
)看上去和侧边栏的链接按钮完全相同。当我们比较HTML标记时:
- 搜索按钮使用的是
<button>
元素 - 但链接按钮使用的是
<a role="button" ...>
元素
虽然两者使用的标签元素不同,但它们使用了相同的类名:.c-btn
和.c-btn--yellow
。
按钮样式是伸缩的,它允许你在任何地方添加外观相同的组件,因为它不会被它的父元素或兄弟元素污染。让你不需要为完全不相关的组件被破坏而头疼,即使在完全不同的位置被另一组件调用。
可扩展的(Extensible)
可扩展的组件可以很容易地提供附加的特性(或功能),而不需要破坏自身而重新编写代码。比如下面的示例:
除了3D效果外,头部和主内容区域中的按钮看起来非常相似。在这种情况下,我们可以通过扩展基础按钮来实现3D按钮效果,而不需要创建完全不同代码的两组按钮。
页脚上的按钮也是如此。即使按钮有不同的颜色和大小,我们也可以通过添加或删除新的或不同的特性来扩展它。
可维护的(Maintainable)
对于大多数前端来说,最大的挑战之一可能是理解其他人或我们自己过去写的CSS。我们有时要花不少的时间去理解现有的代码,而不是添加新的代码。
主要问题来自于:
- 代码中没有任何注释
- 过度的系统设计
- 没有真正的来源
- 没有考虑编码的标准(或最佳实践)
有了SEM和BIO,我们就可以改进代码并将其他人(包括我们自己)从混乱的、不可维护的代码中拯救出来。
BIO
有很多很好的技术可以改进我们写CSS的方式,根据我的经验,我发现下面三种方式就是编写CSS的很好方式之一。他们首字母缩略就组成了BIO:
- BEM
- ITCSS
- OOCSS
很多开发人员(或工程师)知道这些编写CSS的技术,但是我想一一介绍并讨论我使用这些技术的方式。
BEM
BEM是非常流行的方法,它一直在帮助我们显著地改进我们对CSS和Sass(或LESS)的思考方式。BEM其实是下在三个词的缩写:
- Block
- Element
- Modifier
正如上面的示例所显示的那样,很多开发人员过度的使用Sass(或LESS)的力量,并陷入了嵌套的魔咒之中。但是在BEM中,通过在一个(或两个)嵌套层上写样式,保持一个非常低的CSS权重。
如果你曾经因为CSS选择器权重而烦恼,那么使用BEM是多爽。
回到我们的示例,HTML的标记如下所示:
<div class="o-grid">
<div class="o-grid__item o-grid__header">
...
</div>
<div class="o-grid__item o-grid__main">
...
</div>
<div class="o-grid__item o-grid__sidebar">
...
</div>
<div class="o-grid__item o-grid__footer">
...
</div>
</div>
示例包括:
- 一个区块:
.o-grid
- 元素:
.o-grid__item
,.o-grid__header
,.o-grid__main
,.o-grid__sidebar
,.o-grid__footer
由于BEM提供了一种命名约定,强调唯一的类,所以我们不必像下面这样使用多层的嵌套:
.o-grid {
.o-grid__item {
...
}
}
相反,我们可以用更少的层次来定义它的样式:
.o-grid__item {
...
}
这就是BEM最大的优点:降低CSS选择器权重,提高整个CSS编码的效率和体验。
即使是BEM,我偶尔也会遇到一个问题,那就是不好命名。如果你没有足够的注意力,你可能会得到一个很长的类名:
.o-grid__item-search-button-text-svg-icon {
...
}
当你创建一个类名时,使用BEM的核心概念:你的组件是一个块,其中的所有元素都单独地附加到这个块上。
在我们的示例中,使用.o-grid__form
替代.o-grid__item-form
,因为该表单本身是一个单独的组件,不需要与o-grid__item
绑定并成为其子元素。
另外,为了更有效地控制样式,我添加了另一个类名o-grid__header
和o-grid__item
来扩展样式。此外,该按钮包含使用OOCSS方法的BEM样式的类,接下来将介绍这一部分。
OOCSS
正如我们已经讨论过的,有很多很棒的CSS方式可以帮助我们改进CSS编写方式。然而,我看到很多人强迫息决定用一种方法。
根据我的经验,结合方法论,我们编写CSS的时候实际上可以结合多种方法的优势来提高编写代码的效益。例如,我个人发现BEM和OOCSS在一起就是一种很好的组合方式。
OOCSS代表面向对象的CSS,你可以把它想像成乐高积木:
OOCSS分创建很多个单独部分,然后将它们组合在一起,以便构建组件。从我们的示例中,使用OOCSS命名创建了按钮:
.c-btn
.c-btn--yellow
.c-btn--blue
.c-btn--3d
.c-btn--large
在示例中,头部中搜索的按钮,将使用下面的类组合在一起构建的:
.c-btn
.c-btn--yellow
如果我们想要在主要内容区域中创建一个3D的按钮,我们要添加一个3D按钮的类.c-btn--3d
。
对于页脚中的蓝色的按钮,我们可以将黄色修饰符换成蓝色的修饰符,并添加大按钮的修饰符。正如你所看到的,该按钮不依赖于头部区域,这使我们可以更灵活使用和重用组件。通过这样做,我们可以在不影响任何其他组件或模块的情况下构建按钮,同时可以轻松地扩展新的表现特性,比如颜色和形状。
在这里,使用OOCSS创建按钮集合来创建变体的示例:
在BEM和OOCSS的基础上,在ITCSS的帮助下,我们可以进一步改进我们的CSS编写。下面我们来看看ITCSS这个方法。
ITCSS
ITCSS代表的是倒三角CSS(Inverted Triangle CSS),它通过应用一个结构来帮助我们组织CSS代码,这个结构可以确定使用特定组件的具体程序。@Lubos Kmetko写了一篇有关于ITCSS很好的文章,非常值得一读。
你也可以看看我是如何使用ITCSS的,将样式按特定的程度分组是其重要的特点。
基于这个示例,你可以通过向类添加命名空间来查看如何命名组件。因此,比如按钮组件的前缀可以用c
(.c-button
),以指示组件的状态,并防止将其误认为另一项。通过这样做,项目中的每个人都知道这个特定类的功能,以及更改它的属性可能会影响其他的领域。
下图显示所有ITCSS级别:
让我们来看看每个部分。
设置(Settings)
设置通常是不生成CSS的变量集合,而是应用于类。其主要包括:
- 基本(Base)
- 颜色(Color)
- 排版(Typography)
- 动画(Animation)
工具(Tools)
工具也不会产生任何CSS,并且通常是预处理函数,帮助在类上编写或扩展属性:
- 函数(Functions)
- 占位符(Placeholders)
- 混合宏(Mixins)
- 媒体查询(Media Queries)
供应商(Vendors)
供应商是在项目中使用的第三方样式。比如reset.css
、normalize.css
,甚至是Foundation和Bootstrap这样的CSS Frameworks等。
这些样式在结构中较高的原因是,如果我们需要,还可以重写它们。你还记得,如果同一个类被调用两次,比如说两属性完全相同,那么级联将呈现第二个属性。
.btn--large {
padding: 3em;
}
/* 将覆盖第一个 */
.btn--large {
padding: 5em;
}
顺便提一下,在Sass中,你可以使用~
指向node_modules
文件夹,这样你就可以从源代码中导入样式,而不必将其移动到自己的项目目录中。
@import '~modern-normalize/modern-normalize';
对象(Objects)
对象(命名空间以o-
开头)用于设计模式。所有页面都使用对象类,因此如果对象类做任何更改,都应该非常小心,因为任何更改都会影响整个网站的每个页面。
我最常用的对象类是:
.o-page
:最外层的容器,比如在容器中运用max-width: 100vw
和overflow:hidden
.o-main
:主内容区域的外部容器.o-container
:组件的外部容器,通常提供固定的宽度.o-content
:实际内容区域的任何额外配置.o-grid
:网格布局
如果你有使用其他对象类,欢迎与我一起分享。
元素(Elements)
元素(命名空间以e-
开头)是HTML元素,我们不会根据类名对其进行样式化。例如,我们为<a>
元素提供默认样式,而不是添加的类名.link
。
// 链接默认样式
a {
text-decoration: none;
&:hover {
background-color: blue;
color: white;
}
}
// 不要为链接添加类并提供样式
.link {
text-decoration: none;
&:hover {
background-color: blue;
color: white;
}
}
这是因为,特别是在WordPress这样的CMS系统中,你不会希望每次在内容中使用链接时都添加类。因此,我们为<a>
元素提供了一个默认样式,因此没有任何类,链接仍然具有好看的样式。
组件(Components)
组件(命名空间以c-
开头)是构成网站一部分的一个小特性。比如button
、accordions
、sliders
、modal
等。每个组件都是完全独立的,不依赖于任何其他组件。当你命名组件时,应该考虑这个事实。
比如,前面示例中的主内容区域中的按钮不应该被称为c-main-button
,因为main
将它限定在主内容区域中,并限制在其他地方(比如侧边栏)中使用它。像.c-btn
这样的东西会更好,因为按钮不再绑定到页面的其他特定部分。
如果你需要扩展一些其他的特性,你可以使用BEM修饰符扩展属性,或者使用作用域。
模式(Patterns)
许多开发人员(或者工程师)使用的组件术语和模式差不多一个意思,如果你更认同这样的一个概念,也完全没有问题。我只是想把这两部分分开来说。
对于一般的经验法则,我认为模式(命名空间以p-
开头)是组件的组合,但在某种程度上是不何扩展的组件。
例如,我将手风琴(accordion
)作为一个组件。它本身是可伸缩和可重用的,这也意味着它可以在网站的其他区域中使用,即使手风琴会包含其他组件,比如按钮。
另一方面,比如,页头也是一个模式,因为它是不可伸缩的(页头不能在主内容或侧边栏区域中使用),而且也还包含基他组件,比如按钮、手风琴、菜单,微标和搜索表单等。
作用域(Scope)
注意,我只在有必要的情况下才使用作用域。作用域(命名空间以s-
)开头,其目的是为我们提供最高的权重,以例我们可以为特定的目的覆盖任何样式。
请记住,如果你多次使用作用域类,你可能会编写过于具体的样式,你应该考虑重构你的CSS或HTML。
这里有一个使用作用域的类.s-home
:
.c-accordion {
.s-home & {
// 改变主页上手风琴的背景颜色
background-color: tomato;
}
}
补充一点,可以给手风琴提供修饰符(例如:.c-accordion--bg-tomato
)替代作用域的类来得构上面的代码。这将是一种更可扩展的方式,使用组件更加模块化。
扩展命名空间
除了上面讨论的命名空间之外,我还经常使用另外两个命名空间:
is-
:用来表示块或元素的状态。最常用的类是.is-active
,就像导航中当前状态的链接js-
:用来表示特定的元素被绑定到JavaScript事件。例如,js-menu-click
表示元素绑定了click
事件
监测(Linting)
最后,使用.stylelint
和.eslint
制定的规则可以显著提高代码质量。
在前端的工作流中,我不把它作为推荐。在我的工作流中,这是强制的,如果你平时工作中不遵守的话,是通不过的。
通过这种方式,我们可以确保代码质量,并让你的代码保持在最佳状态,并为其他开发人员(包括你未来的自己)提供更好的代码。
实战
在本节中,我将讨论如何使用SEM和BIO。我已做了一个简单而实用的例子。我们就从这个示例开始:
这个示例主要做了一个手风琴,它可以被用作:
- 一种普通的手风琴,但在主内容区域有不同的颜色
- 侧边栏中的菜单
- 在页脚显示社交媒体图标的区块
我们取得的成果是:
- 可伸缩:因为它可以添加到页面的任何部分,而不需要修改任何代码
- 可扩展:因为它可以在不改变核心功能的情况下服务于不同的功能
- 可维护性:因为它的组织方式是有意义的
在示例中使用SEM和BIO的特性主要包括:
- BEM:
.c-accordion
作为一个块,它的子元素也使用了修饰符,比如.c-accordion--light
和.c-accordion--dark
- ITCSS:Sass文件的排序很好处理CSS的权重。例如,在侧边栏中手风琴按钮包含了
class="c-accordion__trigger p-sidebar-menu__button"
。模式p-
会在没有问题的情况下重写组件c-
- OOCSS:手风琴是由几个类组成的,例如
class="c-accordion c-accordion--dark c-accordion--single"
,每次只打开一个面板就会产生一个dark
主题
总结
我几乎在我的所有项目中都使用了这种方法,包括大学、政府部门、商业零售商和许多其他网站。在每一个案例中,我都成功地将所有的项目交付给客户(在客户审批阶段几乎没有问题并按时交付);到目前为止,这种方法对我非常有效,我认为对你也是如此。
话又说回来,技术总是在变化的(特别是前端领域的技术),我很高兴能听到你的想法,更希望有机会能与你一起讨论。如查你有更好的想法或建议欢迎在评论中与我一起分享!
如需转载,烦请注明出处:https://www.w3cplus.com/css/combining-the-powers-of-sem-and-bio-for-improving-css.html