这篇教程我们将学习如何结合BEM和SUIT来使用PostCSS,让编写CSS样式更容易、更有效。
这两个方法都是用来给类命名的,使用它更容易让你将风格紧密结合在一起,并且帮助其他开发人员从各种的类名就能识别出对应的样式风格。
BEM是由@Yandex提出的一种类名命名方式。SUIT是基于BEM上的另一种类名命名方式,只不过@Nicholas Gallagher在BEM的基础上做了一些调整。BEM能做的事情,SUIT都可以做,但很多用户觉得SUIT是BEM的一种改进。
使用这些方法确实有助于产生更好的,理有结构化的CSS。然而,需要的注意的是,手动输入结构所需的类名会让你感到厌烦,并且跟踪这些类以及如何推动,更会让你感到头痛。
@Malte-Maurice Dreyer的postcss-bem
插件通过缩写和嵌套缓解了这些问题。在接下来的教程中你将学习如何使用。
为了确保你能更好的学习或了解postcss-bem
插件的好处和如何使用它,我们有必要先对BEM和SUIT做一个快速的了解。
BEM快速入门
Block
在BEM中Block是设计中的最高一级,整个网站都是由很多个块构建而成。一个块在网站上是独立的,理论上说块可以放置在你的布局的任何一个地方,甚至还可以嵌套在另一个块里面。
例如,在你的网站上的搜索表单块,你就可以使用.search-form
类来表示。
Element
在BEM中的Element其实是Block中的一个元素。使用两个下划线__
将元素的名称附加到其父块的名称后。
例如,一个搜索表单可能包括标题、文本框和提交按钮等元素,那么它们的类名可以命名成:.search-form__heading
,.search-form__text-field
和.search-form__submit-button
。
Modifier
在BEM中Modifier是应用于Block或Element表示改变的描述,或者是状态改变。修饰符名称一般附加在Block或Element的后面。
在BEM的官方网站上,修饰符使用的一个_
做为分隔符。但@Harry Roberts提供了一份类似于BEM的CSS指南规范中(把这种称为BEM-like方法),使用两个破折号--
做为分隔符,而且这种方式比BEM官方提供的命名方式使用更为广泛。
例如,在设计中你可能希望提供一个高级搜索表单的样式不同于常规的搜索表单样式。因为创建了一个修饰符(Modifier)来作为区分:BEM官网的命名方式.search-form_advanced
,BEM-like的命名方式:.search-form--advanced
。
比如例外一个例子,你希望给提交了一个无效内容,而此时你想要改变表单的外观状态。这样你也可以创建一个修饰符。.search-form_invalid
(BEM官方),.search-form__invalid
(BEM-like)。
SUIT快速入门
SUIT包括结构(Utilities)和组件(Components)。组件(Components)中又可以有修饰符(Modifiers)、后代(Descendants)和状态(States)。
SUIT使用Pascal命名法、驼峰命名法和破折号。在BEM中,约定命名使用到的破折号和下划线的数量,常常给人带来困惑。例如,在BEM中的命名方式.search-form__text-field
和SUIT的命名方式.SearchForm-textField
。
Utilities
Utilities是用来处理结构和位置方面的样式,组件中也可以用这种方式来写。常常在驼峰命名前加一个u-
前缀。例如.u-clearFix
。
Components
SUIT中的Components就相当于BEM中的Block。组件的命名方式常常使用pascal命名,也更适合SUIT,使它们更容易识别。例如.SearcForm
。
组件命名空间
组件可以在命名前加一个nmsp-
这样的命名空间,用来防止类名的冲突。比如.mine-SearchForm
。
Descendants
SUIT中的Descendants相当于BEM中的Element。它使用破折号-
和驼峰命名结合在一起来。例如.SearchForm-heading
,.SearchForm-textField
和.SearchForm-submitButto
。
Modifier
SUIT中的Modifier和BEM中的一样,但SUIT对他们的角色控制的更为严格。SUIT中的Modifier只用于组件(Components)上,不用于Dedicated上。它也不能用于表示状态(State)变化,就算要用于状态的变化,SUIT也有自己一套专用的命名约定。
Modifier都用两个破折号--
来连接,例如:SearchForm--advanced
。
State
State是用来反映组件更改的状态。通过不同的修饰词,反映出组件修改后的基本外观。如果有必要,State也可以应用于Descendent中。
State一般都在驼峰命名前添加is-
前缀。如:.SearchForm.is-invalid
。
项目配置
如果SUIT和BEM是你的工作中的必需品,那时候设置你的项目了。
你需要做的第一件事情是使用Gulp或Grunt设置你的项目。如果你没有一个较好的项目模板,你可以使用Gulp或者Grunt使用最少的代码来达到相同的目的。
你可以阅读前面有关于PostCSS的教程,了解有关于如何使用Gulp或Grunt设置您的项目:
如果你不想从头开始手动设置您的项目,你可以下载本教程中提供的源码附件,提取Gulp或Grunt项目到一个空的文件夹中。
然后在命令终端运行:npm install
。
安装插件
接下来,你需要把postcss-bem
插件安装到你的项目中,为了让它能更好的工作,我们还需要安装一个postcss-nested
插件。
不管你使用的是Gulp还是Grunt,运行下面的命令,将插件安装到你的项目文件夹中:
npm install postcss-bem postcss-nested --save-dev
好,现在已经把插件安装到你的项目中了。
通过Gulp加载插件
如果你使用的是Gulp,那么可以在gulpfile.js
文件中添加下面的变量:
var bem = require('postcss-bem');
var nested = require('postcss-nested');
将新添加的变量添加到processors
数组中:
var processors = [
bem,
nested
];
命令行中运行gulp css
命令,做一个快速测试。这个时候你可以看到dest/
文件夹中添加了一个style.css
文件。
通过Grunt加载插件
如果你使用的是Grunt,更新gruntfile.js
文件中的processors
对象,并且给对象嵌套一个options
:
processors: [
require('postcss-bem')(),
require('postcss-nested')()
]
在命令行中运行grunt postcss
做一个快速测试,你会发现在你的项目中的dest/
文件夹中添加了一个新文件style.css
。
好了,你现在都已准备好了。我们接下去就可以学习如何在项目是生成BEM和SUIT结构。
postcss-bem
结合BEM和SUIT使用
手工编写BEM和SUIT结构是很笨拙的开发方式,不断的重复声明相同的类名会变得无聊,而且跟踪起来也很容易混淆。
当你使用postcss-bem
就会变得非常的容易,重复的输入类名就几乎不存在。
生成SUIT结构
默认情况之下postcss-bem
会根据SUIT语法输出,而不是BEM。不过也可以输出BEM语法,稍后我们会介绍。但插件主要还是用来输出SUIT语法,出于这个原因,我们先从SUIT的语法说起。
生成一个组件(Component)
创建一个组件,可以使用@component ComponentName{...}
语法。
在src/style.css
文件中尝试添加一个SearchForm
组件:
@component SearchForm {
padding: 0;
margin: 0;
}
编译出来的结果是:
.SearchForm {
padding: 0;
margin: 0;
}
生成一个Descendent
通过@descendent descName{...}
语法在组件中嵌套,可以创建一个Descendent。
在SearcForm
组件中嵌套一个textField
,添加一个Descendent,如下所示:
@component SearchForm {
padding: 0;
margin: 0;
/* Nest descendent under component */
@descendent textField {
border: 1px solid #ccc;
}
}
编译出来是这样的:
.SearchForm {
padding: 0;
margin: 0;
}
.SearchForm-textField {
border: 1px solid #ccc;
}
生成一个Modifier
通过@modifier name{...}
嵌套在组件内给组件创建一个修饰符Modifier。Modifier通常放在组件的最顶部,他高于任何一个Descendents和States。
在SearcForm
组件中添加一个名叫advanced
的Modifier:
@component SearchForm {
padding: 0;
margin: 0;
/* Typically, place modifiers above descendents */
@modifier advanced {
padding: 1rem;
}
@descendent textField {
border: 1px solid #ccc;
}
}
重新编译你的代码,你会看到Component中添加了一个advanced
的Modifier:
.SearchForm {
padding: 0;
margin: 0;
}
.SearchForm--advanced {
padding: 1rem;
}
.SearchForm-textField {
border: 1px solid #ccc;
}
生成一个State
通过@when name {...}
语法嵌套在一个组件(Component)或一个Descendent中可以创建一个State。
在textField
添加一个invalid
,给textField
的Descendent添加一个名为invalid
的State:
@component SearchForm {
padding: 0;
margin: 0;
@modifier advanced {
padding: 1rem;
}
@descendent textField {
border: 1px solid #ccc;
/* This creates a state for the textField descendant */
@when invalid {
border: 1px solid red;
}
}
}
编译出来的代码会包括一个名为invalid
的State:
.SearchForm {
padding: 0;
margin: 0;
}
.SearchForm--advanced {
padding: 1rem;
}
.SearchForm-textField {
border: 1px solid #ccc;
}
.SearchForm-textField.is-invalid {
border: 1px solid red;
}
组件全名空间
通过@component-namespace name {...}
可以给组件(Components)创建命名空间,而且Descendents,Modifiers和States都嵌套在里面。如果你喜欢,整个样式表都可以采用命名空间,而且可以自动添加到类的前面。
使用@component-namespace mine{...}
给容器添加一个命名空间:
@component-namespace mine {
@component SearchForm {
padding: 0;
margin: 0;
@modifier advanced {
padding: 1rem;
}
@descendent textField {
border: 1px solid #ccc;
@when invalid {
border: 1px solid red;
}
}
}
}
编译出来的代码,会在你的组件前添加一个mine-
前缀。如:
.mine-SearchForm {
padding: 0;
margin: 0;
}
.mine-SearchForm--advanced {
padding: 1rem;
}
.mine-SearchForm-textField {
border: 1px solid #ccc;
}
.mine-SearchForm-textField.is-invalid {
border: 1px solid red;
}
生成一个Utility
使用@utility utilityName{...}
创建Utility。你可能还记得,在创建你的项目时,已经安装了postcss-nested
插件。我们这样做,是因为我们使用嵌套能更好的和postcss-bem
达到一致效果,如下面的的例子,我们创建了一个clearFix
:
@utility clearFix {
&:before, &:after {
content: "";
display: table;
}
&:after {
clear: both;
}
/* If supporting IE 6/7 */
*zoom: 1;
}
编译之后,你可以看到下面的代码:
.u-clearFix {
/* If supporting IE 6/7 */
zoom: 1;
}
.u-clearFix:before, .u-clearFix:after {
content: "";
display: table;
}
.u-clearFix:after {
clear: both;
}
生成BEM结构
在你的gulpfile.js
或gruntfile.js
文件中设置style:'bem'
,可以指定postcss-bem
插件输出代码是按BEM的语法。
/* Gulpfile */
var processors = [
bem({style: 'bem'}),
nested
];
/* Gruntfile */
processors: [
require('postcss-bem')({style: 'bem'}),
require('postcss-nested')()
]
默认情况之下postcss-bem
插件将使用一个下划线_
。更重要的是根据你的项目,你也可以使用两个破折号--
做为分离器。你也可以修改node_modules/postcss-bem
文件夹下的index.js
文件,修改第15
行代码,你就可以重新配置postcss-bem
插件的分离器符号:
bem: {
separators: {
namespace: '--',
descendent: '__',
modifier: '_'
}
}
修改成:
bem: {
separators: {
namespace: '_',
descendent: '__',
modifier: '--'
}
}
生成一个Block
BEM中的Block就相当于SUIT中的Component。使用@component block-name{...}
就可以生成一个Block。
添加下面的代码就可以创建一个search-form
的Block:
@component search-form {
padding: 0;
margin: 0;
}
编译出来的代码如下:
.search-form {
padding: 0;
margin: 0;
}
生成一个Element
BEM中的Element就相当于SUIT中的Descendent。你可以使用@descendent element-name{...}
嵌套在Block中,创建一个Element。
你可像下面的代码一样,创建一个名为text-field
的Element:
@component search-form {
padding: 0;
margin: 0;
@descendent text-field {
border: 1px solid #ccc;
}
}
编译之后,你就能看到一个新的Element就创建了:
.search-form {
padding: 0;
margin: 0;
}
.search-form__text-field {
border: 1px solid #ccc;
}
生成一个Modifier
尽管BEM允许给Block和Element创建一个Modifier,但postcss-bem
插件只会处理嵌套在Block中的Modifier,而不会创建嵌套在Element的Modifier。这主要是因为Component有Modifier,而Descendent没有Modifier。可以通过@modifier name{...}
语法,将Modifier嵌套在它的父块中。
可以像下面的代码一样,给search-form
添加一个advanced
的Modifier:
@component search-form {
padding: 0;
margin: 0;
@modifier advanced {
padding: 1rem;
}
@descendent text-field {
border: 1px solid #ccc;
}
}
编译出来的代码如下:
.search-form {
padding: 0;
margin: 0;
}
.search-form_advanced {
padding: 1rem;
}
.search-form__text-field {
border: 1px solid #ccc;
}
没有Utility和State,但有命名空间
在BEM模式中没有@utility
和@when
语法,它们不会编译成任何东西,所以在BEM中不要使用Utility或State。
然而,尽管他们不属于BEM中的一部分,但@component-namespace
语法仍然能工作,也能使用到你的样式表中。它将给你的类名添加一个类似name--
的前缀。
.mine--search-form {
padding: 0;
margin: 0;
}
.mine--search-form_advanced {
padding: 1rem;
}
.mine--search-form__text-field {
border: 1px solid #ccc;
}
做个总结
现在你知道如何生成BEM和SUIT的结构,并且使整个过程更容易。让我们来总结一下:
- BEM和SUIT是面向类名的一种规范,帮助你更好的组织样式,以及更好的帮助其他开发人员能识别各种类的目的
- SUIT就像BEM,但额外的做了一些调整
postcss-bem
插件提供了创建BEM和SUIT的类,如@component
,@descendent
和@modifier
等- 插件还允许代码嵌套,如Modifier嵌套在Component或Block中
- 使用
@component-namespace name{...}
可以自动给容器创建命名空间
下一节
在下一篇教程中,将会看到使用PostCSS的更好方法,那就是通过一个提示工具,让我们编码更快更有效,而这个工具包装了速记(Shorthand)和一些快捷方式。如果您对这方面的知识感兴趣的话,欢迎持续关注这个系列教程的相关更新。
本文根据@Kezz Bracey的《Using PostCSS with BEM and SUIT Methodologies》所译,整个译文带有我们自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:http://webdesign.tutsplus.com/tutorials/using-postcss-with-bem-and-suit-methodologies--cms-24592。
如需转载,烦请注明出处:http://www.w3cplus.com/PostCSS/using-postcss-with-bem-and-suit-methodologies.html