以前看過(guò)一些CSS的編碼規(guī)范驳癌,也照著規(guī)范編寫代碼娄琉,但是還是覺(jué)得自己的CSS編碼風(fēng)格不是很好融击,在平時(shí)開發(fā)中使用各個(gè)知名的組件庫(kù)的時(shí)候筑公,發(fā)現(xiàn)現(xiàn)在挺多組件庫(kù)都是BEM的命名風(fēng)格了,于是找了比較知名的element餓了么前端的組件庫(kù)的源碼砚嘴,想從看餓了么組件庫(kù)的代碼入手十酣,學(xué)習(xí)學(xué)習(xí)大廠的的CSS BEM規(guī)范代碼的書寫風(fēng)格。
BEM代表“塊(block)际长,元素(element)耸采,修飾符(modifier)”,開發(fā)組件的過(guò)程中經(jīng)常使用這三個(gè)實(shí)體工育,而在選擇器中虾宇,這三個(gè)實(shí)體由以下符號(hào)來(lái)表示擴(kuò)展關(guān)系:
- 中劃線:僅作為連字符使用,表示某個(gè)塊或者某個(gè)子元素的多單詞之間的連接記號(hào)如绸。
__ 雙下劃線:雙下劃線用來(lái)連接塊和塊的子元素嘱朽。
_ 單下劃線:?jiǎn)蜗聞澗€用來(lái)描述一個(gè)塊或者塊的子元素的一種狀態(tài)。
type-block__element_modifier
以上的描述是從騰訊的前端規(guī)范庫(kù)中找到的怔接,簡(jiǎn)單的來(lái)說(shuō)理解了塊搪泳、元素、修飾符三個(gè)分類之后扼脐,就能大致理解BEM代碼是什么樣的結(jié)構(gòu)了岸军,可是了解結(jié)構(gòu)是一方面,如何寫好代碼又是另一方面瓦侮。我在element組件庫(kù)中的mixins.scss
文件中找到了想要的答案艰赞。
接下來(lái)我要講的就是如何利用sass,編寫具有可讀性和可維護(hù)性的BEM規(guī)則的css代碼肚吏。
首先來(lái)看sass代碼中對(duì)于block的定義:
$namespace: 'el';
$element-separator: '__';
$modifier-separator: '--';
$state-prefix: 'is-';
@mixin b($block) {
$B: $namespace+'-'+$block !global;
.#{$B} {
@content;
}
}
為了方便大家理解代碼方妖,我現(xiàn)在開頭貼上配置文件中定義的變量,而這時(shí)就能很清楚的看到block的生成就是基于BEM規(guī)范中罚攀,塊是設(shè)計(jì)或布局的一部分党觅,具有唯一地意義雌澄,利用命名空間el
加上中劃線,以及傳入的block的名字仔役,構(gòu)建出block的樣式掷伙,例如alert
組件,在渲染完成后是el-alert
又兵,體現(xiàn)出它的唯一性任柜。而在塊的內(nèi)部,再來(lái)編寫跟這個(gè)塊關(guān)聯(lián)的其他樣式代碼沛厨。
塊的構(gòu)建非常的簡(jiǎn)單宙地,接下來(lái)來(lái)看稍微有點(diǎn)復(fù)雜的元素的定義:
@mixin e($element) {
$E: $element !global;
$selector: &;
$currentSelector: "";
@each $unit in $element {
$currentSelector: #{$currentSelector + "." + $B + $element-separator + $unit + ","};
}
@if hitAllSpecialNestRule($selector) {
@at-root {
#{$selector} {
#{$currentSelector} {
@content;
}
}
}
} @else {
@at-root {
#{$currentSelector} {
@content;
}
}
}
}
元素選擇器的實(shí)現(xiàn)中,我們應(yīng)該把關(guān)注點(diǎn)放在if和eles分支上逆皮,為什么會(huì)出現(xiàn)hitAllSpecialNestRule
函數(shù)判斷的分支宅粥,原因是在修飾符或者其他mixin中嵌套一個(gè)元素element,會(huì)出現(xiàn)修飾符在前电谣,而元素在后的編譯結(jié)果秽梅,所以我們用hitAllSpecialNestRule
函數(shù)來(lái)判斷是否存在特殊的嵌套,如果存在的話剿牺,將我們的元素字符串寫在前面企垦,而修飾符放在后面,如果不存在晒来,則原樣輸出钞诡。
而hitAllSpecialNestRule
的實(shí)現(xiàn)則在下面的代碼中:
@function selectorToString($selector) {
$selector: inspect($selector);
$selector: str-slice($selector, 2, -2);
@return $selector;
}
@function containsModifier($selector) {
$selector: selectorToString($selector);
@if str-index($selector, $modifier-separator) {
@return true;
} @else {
@return false;
}
}
@function containWhenFlag($selector) {
$selector: selectorToString($selector);
@if str-index($selector, '.' + $state-prefix) {
@return true
} @else {
@return false
}
}
@function containPseudoClass($selector) {
$selector: selectorToString($selector);
@if str-index($selector, ':') {
@return true
} @else {
@return false
}
}
@function hitAllSpecialNestRule($selector) {
@return containsModifier($selector) or containWhenFlag($selector) or containPseudoClass($selector);
}
第一個(gè)函數(shù)selectorToString
,就是將我們的選擇器轉(zhuǎn)換成一個(gè)字符串湃崩,而接下來(lái)的三個(gè)函數(shù)荧降,分別判斷了是否存在修飾符、flag例如(.isCenter)攒读、偽類的情況朵诫。最后綜合在一起返回結(jié)果,避免嵌套薄扁。
最后則是modifier
修飾符的實(shí)現(xiàn)了拗窃,代碼如下:
@mixin m($modifier) {
$selector: &;
$currentSelector: "";
@each $unit in $modifier {
$currentSelector: #{$currentSelector + & + $modifier-separator + $unit + ","};
}
@at-root {
#{$currentSelector} {
@content;
}
}
}
在看懂的元素的實(shí)現(xiàn)之后,修飾符的實(shí)現(xiàn)就是一目了然的了泌辫。利用剛剛介紹的函數(shù),以及塊九默、元素震放、修飾符的實(shí)現(xiàn)代碼,在sass中已經(jīng)能非常高效率并且優(yōu)雅的基于BEM規(guī)范的代碼了驼修。
貼一段示例代碼殿遂,如何利用上面的代碼編寫B(tài)EM規(guī)范的css代碼:
@import "mixins/mixins";
@import "common/var";
@include b(test) {
width: 100%;
background-color: $--color-white;
@include when(center) {
justify-content: center;
}
@include m(success) {
background-color: $--color-black;
font-size: 12px;
.lix-test__description {
color: $--color-white;
}
}
@include m(warning) {
background-color: $--color-black;
font-size: 12px;
.lix-test__description {
color: $--color-white;
}
}
@include e(content) {
display: table-cell;
padding: 0 8px;
}
@include e(title) {
font-size: 8px;
line-height: 10px;
@include when(bold) {
font-weight: bold;
}
}
}
.lix-test-fade-enter,
.lix-test-fade-leave-active {
opacity: 0;
}
編譯之后的樣子:
.lix-test {
width: 100%;
background-color: #fff; }
.lix-test.is-center {
justify-content: center; }
.lix-test--success {
background-color: #000;
font-size: 12px; }
.lix-test--success .lix-test__description {
color: #fff; }
.lix-test--warning {
background-color: #000;
font-size: 12px; }
.lix-test--warning .lix-test__description {
color: #fff; }
.lix-test__content {
display: table-cell;
padding: 0 8px; }
.lix-test__title {
font-size: 8px;
line-height: 10px; }
.lix-test__title.is-bold {
font-weight: bold; }
.lix-test-fade-enter,
.lix-test-fade-leave-active {
opacity: 0; }
瞧見了么诈铛,合理的利用b、m墨礁、e的mixin就可以風(fēng)格良好的css代碼了幢竹。上面的所有代碼都在這里哦,有需要的可以直接看完整代碼學(xué)習(xí)恩静。