这篇教程我们将学习如何结合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是设计中的最高一级,整个网站都是由很多个块构建而成。一个块在网站上是独立的,理论上说块可以放置在你的布局的任何一个地方,甚至还可以嵌套在另一个块里面。
例如,在你的网站上的搜索表单块,你就可以使用 .search-form
类来表示。
在BEM中的Element其实是Block中的一个元素。使用两个下划线 __
将元素的名称附加到其父块的名称后。
例如,一个搜索表单可能包括标题、文本框和提交按钮等元素,那么它们的类名可以命名成: .search-form__heading
, .search-form__text-field
和 .search-form__submit-button
。
在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包括结构(Utilities)和组件(Components)。组件(Components)中又可以有修饰符(Modifiers)、后代(Descendants)和状态(States)。
SUIT使用 Pascal命名法 、 驼峰命名法 和破折号。在BEM中,约定命名使用到的破折号和下划线的数量,常常给人带来困惑。例如,在BEM中的命名方式 .search-form__text-field
和SUIT的命名方式 .SearchForm-textField
。
Utilities是用来处理结构和位置方面的样式,组件中也可以用这种方式来写。常常在驼峰命名前加一个 u-
前缀。例如 .u-clearFix
。
SUIT中的Components就相当于BEM中的Block。组件的命名方式常常使用pascal命名,也更适合SUIT,使它们更容易识别。例如 .SearcForm
。
组件可以在命名前加一个 nmsp-
这样的命名空间,用来防止类名的冲突。比如 .mine-SearchForm
。
SUIT中的Descendants相当于BEM中的Element。它使用破折号 -
和驼峰命名结合在一起来。例如 .SearchForm-heading
, .SearchForm-textField
和 .SearchForm-submitButto
。
SUIT中的Modifier和BEM中的一样,但SUIT对他们的角色控制的更为严格。SUIT中的Modifier只用于组件(Components)上,不用于Dedicated上。它也不能用于表示状态(State)变化,就算要用于状态的变化,SUIT也有自己一套专用的命名约定。
Modifier都用两个破折号 --
来连接,例如: SearchForm--advanced
。
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,那么可以在 gulpfile.js
文件中添加下面的变量:
var bem = require('postcss-bem'); var nested = require('postcss-nested');
将新添加的变量添加到 processors
数组中:
var processors = [ bem, nested ];
命令行中运行 gulp css
命令,做一个快速测试。这个时候你可以看到 dest/
文件夹中添加了一个 style.css
文件。
如果你使用的是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
就会变得非常的容易,重复的输入类名就几乎不存在。
默认情况之下 postcss-bem
会根据SUIT语法输出,而不是BEM。不过也可以输出BEM语法,稍后我们会介绍。但插件主要还是用来输出SUIT语法,出于这个原因,我们先从SUIT的语法说起。
创建一个组件,可以使用 @component ComponentName{...}
语法。
在 src/style.css
文件中尝试添加一个 SearchForm
组件:
@component SearchForm { padding: 0; margin: 0; }
编译出来的结果是:
.SearchForm { padding: 0; margin: 0; }
通过 @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 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; }
通过 @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 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; }
在你的 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: '--' } }
BEM中的Block就相当于SUIT中的Component。使用 @component block-name{...}
就可以生成一个Block。
添加下面的代码就可以创建一个 search-form
的Block:
@component search-form { padding: 0; margin: 0; }
编译出来的代码如下:
.search-form { padding: 0; margin: 0; }
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; }
尽管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; }
在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的结构,并且使整个过程更容易。让我们来总结一下:
postcss-bem
插件提供了创建BEM和SUIT的类,如 @component
, @descendent
和 @modifier
等 @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 。
常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。中国Drupal社区核心成员之一。对HTML5、CSS3和Sass等前端脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《 图解CSS3:核心技术与案例实战 》。