BEM 在 Sass 3.4 中的提升
Sass3.4 增加了对父选择器的处理,主要是帮助你更好的处理选择器。我想这是为了更好的使用 mixins
来定义 BEM。
.test {
@debug type-of(&); //打印出.test
}
.test li a{
$selector: &;
test: $selector;//打印出.test li a
}
Sass 3.3 中父选择器的问题
自从选择器能结合任何字符串时,父选择器在 Sass3.3 中就可以正常工作。这篇文章很好的阐述了BEM在Sass3.3能很好的运行,这也是其新特性之一。
虽然下面这段代码是有效的,但是直到现在都无法通过 mixins
来调用类:
.block {
&__element {
background: green;
}
}
这样照样不能正常运行:
@mixin element($selector) {
#{&}__element {
@content;
}
}
.block {
@include element(element){
//mixin ‘element’ 依旧不能连接其父选择器
}
}
你无法创建一个mixins
,让block
成为element
和modifier
的前缀,而且element
和modifier
也不知道他们自己是围绕着哪个block
。
在 Sass 3.4 中改进父选择器的可能性
在Sass3.4中打印出来的选择器可以是一个列表。所以我们可以这样使用mixins
:
$elementSeparator: "__";
$modifierSeparator: "--";
@mixin b($block) {
.#{$block} {
@content;
}
}
@mixin e($element) {
@at-root {
#{&}#{$elementSeparator + $element} {
@content;
}
}
}
@mixin m($modifier) {
@at-root {
#{&}#{$modifierSeparator + $modifier} {
@content;
}
}
}
接下来可以这样使用:
@include b(test) {
background: red;
@include e(element) {
font-size: 14px;
@include m(big) {
font-size: 18px;
}
};
@include m(modifier) {
color: blue;
}
}
//output CSS
.test {
background: red;
}
.test__element {
font-size: 14px;
}
.test__element--big {
font-size: 18px;
}
.test--modifier {
color: blue;
}
然而我还遇到几个问题。第一个问题就是在修饰符modifier
中嵌套一个元素element
。例如下面的这段Sass代码:
@include b(test) {
background: red;
@include m(modifier) {
color: blue;
@include e(subelement) {
background: gray;
}
}
}
//output CSS
.test {
background: red;
}
.test--modifier {
color: blue;
}
.test--modifier__subelement {
background: gray;
}
这其实不是我想要的结果。实际上我想在修饰符下面嵌套一个元素(如.test--modifier .test__subelement
)。我实现这样的目标,我们可以检测 $modifierSeparator
是不是含有选择器字符串(' — —')。如果存在,不想添加更多的后缀,改成一个嵌套选择器。实现这个可以创建一个函数来检测。
如果父选择器返回的是列表类型,需要先将其转换成一字符串。下面的函数就是用来做这件事:
@function selectorToString($selector) {
$selector: inspect($selector); //cast to string
$selector: str-slice($selector, 2, -2); //remove bracket
@return $selector;
}
接下来把 selectorToString()
函数放在 containsModifier()
函数中,做一些字符串的处理:
@function containsModifier($selector) {
$selector: selectorToString($selector);
@if str-index($selector, $modifierSeparator) {
@return true;
}
@else {
@return false;
}
}
除此之外,还需要在 block
选择器外做分割,因为我们是想在 block
中追加 element
而不是 modifier
:
@function getBlock($selector) {
$selector: selectorToString($selector);
$modifierStart: str-index($selector, $modifierSeparator) — 1;
@return str-slice($selector, 0, $modifierStart);
}
将他们都放到一个函数,他接收的是一个选择器,并且检测其是否含有一个 modifier
,然后匹配对应选择器:
@mixin e($element) {
$selector: &;
$block: getBlock($selector);
@if containsModifier($selector) {
@at-root {
#{$selector} {
#{$block+$elementSeparator+$element} {
@content;
}
}
}
}
@else {
@at-root {
#{$selector+$elementSeparator+$element} {
@content;
}
}
}
}
这个时候使用下面的代码:
@include b(test) {
background: red;
@include m(modifier) {
color: blue;
@include e(subelement) {
background: gray;
}
}
}
编译出来的CSS代码:
.test {
background: red;
}
.test--modifier {
color: blue;
}
.test--modifier .test__subelement {
background: gray;
}
最后的代码如下:
$elementSeparator: '__';
$modifierSeparator: '--';
@function containsModifier($selector) {
$selector: selectorToString($selector);
@if str-index($selector, $modifierSeparator) {
@return true;
} @else {
@return false;
}
}
@function selectorToString($selector) {
$selector: inspect($selector); //cast to string
$selector: str-slice($selector, 2, -2); //remove brackets
@return $selector;
}
@function getBlock($selector) {
$selector: selectorToString($selector);
$modifierStart: str-index($selector, $modifierSeparator) - 1;
@return str-slice($selector, 0, $modifierStart);
}
@mixin b($block) {
.#{$block} {
@content;
}
}
@mixin e($element) {
$selector: &;
@if containsModifier($selector) {
$block: getBlock($selector);
@at-root {
#{$selector} {
#{$block+$elementSeparator+$element} {
@content;
}
}
}
} @else {
@at-root {
#{$selector+$elementSeparator+$element} {
@content;
}
}
}
}
@mixin m($modifier) {
@at-root {
#{&}#{$modifierSeparator+$modifier} {
@content;
}
}
}
实际运用如下:
@include b(block) {
background: red;
@include e(header){
font-size: 14px;
@include m(css) {
font-size: 18px;
}
};
@include m(book) {
color: blue;
@include e(kindlebook) {
background: gray;
}
}
}
编译出来的 CSS:
.block {
background: red;
}
.block__header {
font-size: 14px;
}
.block__header--css {
font-size: 18px;
}
.block--book {
color: blue;
}
.block--book .block__kindlebook {
background: gray;
}
总结
在Sass3.3中可以很容易使用BEM,但会有一定的限制性,如今在Sass3.4中可以说BEM的使用更简单。可以让你的代码量很小,简洁易懂,而且还易于维护。我希望我的这个思路能给你带来一定的灵感,让给你带来方便,更希望你也能在些基础上创新。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论