https://medium.com/@andersonorui_/bem-sass-and-bootstrap-9f89dc07d20fjavascript
Bootstrap是一個「HTML,CSS和Javascript的框架,用於開發responsive,mobile first project";css
SASS是一個css擴展預編譯工具;html
BEM是一個解決css可維護可擴展的方法原則java
我一般使用LESS,一個緣由是Bootstrap自己是Less寫的。注意SASS和LESS有一些區別可能會讓你感受很奇怪:web
變量覆蓋的原則不一樣: LESS:後面定義的會覆蓋前面的,而且在整個代碼中都之後面定義的值爲準;SASS則是先定義的會先生效直到遇到從新覆蓋定義爲止。express
注意這個區別對你使用LESS/SASS來開發bootstrap的定製設計時,好比variable.less/sass文件(也就是所謂bootstrap.theme.less),其位置就很重要了,對於less,則須要你的客製化variable放到後面引入,而對於sass則須要最先引入。json
如今已經不多使用photoshop或者illustrator了,幾乎全部工做從項目開始時就直接在html/css/js中進行,固然有時可能我會使用sketch3來作一下brainstrom或者建立ui elements。也正由於此,個人代碼愈來愈亂,以致於不得不重構代碼。固然這個workflow也是我所喜歡的,由於在項目啓動時咱們幾乎不知道咱們打算如何去解決問題,咱們沒法看到全部的patterns,深思熟慮有些浪費時間,因此我每每喜歡在當項目有一個始終一致的模樣時纔來作這個工做。這樣可能更有效果。bootstrap
重構以前我可能有下面的html markup,sass
<div id=」social-newsletter」> <div class=」container」> <header class=」text-center」> <h1 class=」bottom top」>Acompanhe as novidades</h1> </header> <div class=」row」> <div class=」social col-xs-6 col-sm-2 col-md-2"> <div class=」facebook block」> <div class=」centered」> <a href=」http://www.facebook.com" title=」Facebook」> <span class=」sr-only」>facebook</span> <span class=」fa fa-facebook fa-4x」></span> </a> </div> </div> </div> <div class=」social col-xs-6 col-sm-2 col-md-2"> <div class=」twitter block」> <div class=」centered」> <a href=」http://www.twitter.com" title=」Twitter」> <span class=」sr-only」>twitter</span> <span class=」fa fa-twitter fa-4x」></span> </a> </div> </div> </div> <div class=」social col-xs-6 col-sm-2 col-md-2"> <div class=」youtube block」> <div class=」centered」> <a href=」http://www.youtube.com" title=」YouTube」> <span class=」sr-only」>youtube</span> <span class=」fa fa-youtube fa-4x」></span> </a> </div> </div> </div> <div class=」social col-xs-6 col-sm-2 col-md-2"> <div class=」instagram block」> <div class=」centered」> <a href=」http://www.instagram.com" title=」Instagram」> <span class=」sr-only」>instagram</span> <span class=」fa fa-instagram fa-4x」></span> </a> </div> </div> </div> <div class=」newsletter col-xs-12 col-sm-4 col-md-4"> <form> <div class=」block」> <label class=」centered」>Assine nossa newsletter</label> </div> <input type=」email」 placeholder=」Insira seu email」 class=」col-xs-12 col-sm-12 col-md-12"></input> <button type=」submit」 class=」btn btn-danger col-xs-12 col-sm-12 col-md-12">Cadastrar email <i class=」fa fa-paper-plane fa-2x pull-right」></i></button> </form> </div> </div> </div> </div>
經過以BEM方法論,SASS工具支持,可能優化爲下面的樣子:架構
<div class=」social-links js-social-links」> <header class=」social-links—header」> <h1>Acompanhe as novidades</h1> </header> <div class=」social-links—content」> <div class=」social-links—link js-social-link」> <a class=」link—facebook」 href=」http://www.facebook.com" title=」Facebook」> <span class=」sr-only」>facebook</span> <span class=」fa fa-facebook」></span> </a> </div> <div class=」social-links—link js-social-link」> <a class=」link—twitter」 href=」http://www.twitter.com" title=」Twitter」> <span class=」sr-only」>twitter</span> <span class=」fa fa-twitter」></span> </a> </div> <div class=」social-links—link js-social-link」> <a class=」link—youtube」 href=」http://youtube.com" title=」YouTube」> <span class=」sr-only」>youtube</span> <span class=」fa fa-youtube」></span> </a> </div> <div class=」social-links—link js-social-link」> <a class=」link—instagram」 href=」http://www.instagram.com" title=」Instagram」> <span class=」sr-only」>instagram</span> <span class=」fa fa-instagram」></span> </a> </div> <form class=」social-links—newsletter js-newsletter」> <label class=」newsletter—label」><span>Assine nossa newsletter</span></label> <input class=」newsletter—input」 type=」email」 placeholder=」Insira seu email」/> <button class=」newsletter—submit」 type=」submit」><span>Cadastrar email</span></button> </form> </div> </div>
獲得的UI效果是這個樣子的:
爲了達成上面的畝i奧--更加可讀,可理解和富含語義,我須要理解SASS是如何工做的,以及BEM後面所隱含的概念。
BEM是block,element,modifier的首字母縮寫。它的核心想法是經過遵循一套規則使得everything modular---這樣將易於重用易於維護,也更加容易理解和自描述。從BEM網站上,咱們摘抄如下:
「A block is A logically and functionally independent page component, the equivalent of a component in Web Components. A block encapsulates behavior (JavaScript), templates, styles (CSS), and other implementation technologies. Blocks being independent allows for their re-use, as well as facilitating the project development and support process.Blocks can be implemented in one or more technologies, for example:
"
A block can be either simple or compound(containing other blocks),好比下面的例子是一個search form block:
「An element is a part of a block that performs a certain function. Elements are context-dependent: they only make sense in the context of the block they belong to.」
例如:一個input field和一個button是構成search block的elements:
「A modifier is a property of a block or an element that alters its look or behavior.」
blocks和elements一塊兒構成了page content。除了簡單地布放在頁面上,他們的安排也很是重要。Blocks(or elements)可能按照必定的順序一個挨着一個的排列。例如,在一個電商網站上,商品一個個羅列:
或者好比menu items:
Blocks也可能被包含在其餘的block中,好比,一個Head Block包含了logo,searchbox,authblock,menu block。
並且,咱們的building blocks須要一種使用plain text的方式來描述頁面的佈局。爲了實現這一點,每個block和element都須要很好的命名。Block names應該在整個項目範圍內是惟一的;只有相同的block的不一樣實例化須要使用徹底相同的block類,Element名稱必須在所屬block範圍內惟一,一個element能夠被在block範圍內被重複使用任意次數。
但願瞭解更多,能夠直接訪問BEM的網站: http://bem.info/method/definitions/
總結如下,BEM的想法就是要建立一個下面的元素組織架構:
- block
- block__element
- block__element__modifier
<div class="menu menu_hidden"> <span class="menu__item"></span> </div> <div class="menu menu_theme_morning-forest"> <span class="menu__item"></span></div>
{ block: 'page', content: { block: 'head', content: [ { block: 'menu', content: ... }, { elem: 'column', content: { block: 'logo' } }, { elem: 'column', content: [ { block: 'search', content: [ { elem: 'input' }, { elem: 'button', content: 'Search' } ] } ] }, { elem: 'column', content: { block: 'auth', content: ... } } ] } }
element和block能夠互相包含。。。
通常來講,隨着項目的發展,blocks傾向於被添加,被刪除或者在頁面上被移動。好比,你可能但願調換logo和auth block的位置,或者但願將menu放到search block的下方,爲了讓這個變動過程更加方便簡單,要求blocks必須是independent互相獨立的
所謂independent block是以容許放置在頁面中的任何地方的方式來實現的,包括隨意地嵌入到其餘的block中。
從css角度來看這意味着:一個block(or an element)必須有一個惟一的"name"(a css class);HTML elements必須不能在CSS selectors(.menu td)中使用,由於這些包含html tag的selectors固有地不具備context-free的特性;Cascading selectors for several blocks should be avoided:不要使用層疊特性!
一種可能的命名方案是:
<ul class="menu"> <li class="menu__item"> ... </li> <li class="menu__item"> ... </li> </ul>
頗有必要將block name包含在一個element的css class name中,由於這將最小化層疊的可能。同時注意使用一致的seperator(這裏使用的是__),這對於容許自動化的工具介入開發流程頗有幫助。
固然你可使用其餘的命名方式,咱們推薦的方式是:
從模版引擎的角度來看,block independence意味着:
咱們若是須要建立一個和已經存在的一個block很是接近的block,可是可能外觀稍微有些區別,好比,咱們有這樣一個任務:
在footer區域增長一個menu block,使用另一種layout
爲了不再開發另一個block,咱們可使用一個Modifier.
一個Modifier是一個block或者element的屬性,該屬性僅僅改變block/element的外觀或者行爲。一個modifier有一個name和value,多個modifier能夠同時使用。
好比,一個block modifer specifies background color,再好比一個元素的modifier更改look of the "current"item.
從input data角度來看,在一個BEM tree中,modifier是一個描述block/element的實體屬性
<b:menu m:size="big" m:type="buttons"> ... </b:menu>
一樣地,能夠是有那個json來描述
{ block: 'menu', mods: [ { size: 'big' }, { type: 'buttons' } ] }
從css角度來看,一個modifier是一個額外的css 類用於修飾block或者element
<ul class="menu menu__size-big menu__type-buttons"> ... </ul> .menu_size_big { // CSS code to specify height } .menu_type_buttons .menu__item { // CSS code to change item's look }
一樣地,對於element modifier能夠以相似的方式來實現,好比current menu item能夠這樣來實現:
<b:menu> <e:item>Index<e:item> <e:item m:state="current">Products</e:item> <e:item>Contact<e:item> </b:menu> { block: 'menu', content: [ { elem: 'item', content: 'Index' }, { elem: 'item', mods: { 'state' : 'current' }, content: 'Products' }, { elem: 'item', content: 'Contact' } ] }
<div class="menu"> <ul class="menu__layout"> <li class="menu__layout-unit"> <div class="menu__item">Index</div> </li> <li class="menu__layout-unit"> <div class="menu__item menu__item_state_current">Products</div> </li> <li class="menu__layout-unit"> <div class="menu__item">Contact</div> </li> </ul> </div> .menu__item_state_current { font-weight: bold; }
一個website有一個Button block,該block可能包含特定的動態行爲,好比當一個block被hover時,要求更改它的appearance.
manager可能會問:在另一個page中使用一樣的button.
雖然對於一個block有了css implementation,可是這是不夠的。重用一個block也意味着重用它的行爲,而該行爲使用javascript來描述。
因此一個block必須知道關於它本身的全部事情。爲了實現一個block,咱們使用各類技術來描述他的外觀和行爲---咱們稱之爲multilingualism.
Multilingualism presentation是一個對block從各個programming languages的角度來描述的方法,該方法可以準確描述清楚該block的view和functionality。
To have a block present on a page as a UI element, we need to implement it in the following techs:
若是一個block有動態的behaviour,咱們還須要添加
everything that constitues a block is a technology, including images.
http://www.smashingmagazine.com/a-new-front-end-methodology-bem-blocks-reiteration/
咱們先來理解咱們想達到的目標而且理解layout的結構:
而後咱們須要定義屬於不一樣context的咱們的類了:
1.首先定義整個context block .social-links
2.在.social-links裏面,建立兩個其餘的blocks: .social-links--header和.social-links--content
3.在.social-links--header中只有一個h1,惟一的元素;
4。在.social-links--content block中,有四個elements(.social-links--link)和一個block(.social-links--newsletter)
5.在.social-links--newsletter block中,我有3個elements: .newsletter--label,.newsletter--input,.newsletter--button
或許,嚴格按照BEM命名規範,我須要使用.social-links--newsletter--label,.social-links--newsletter--input,可是我知道我不會在其餘地方使用這個newsletter block,因此就簡化爲一個短小的class了(實際上這個假設自己應該是有問題的!)
BEM方法論使得建立一個class是很簡單的,你只須要知道context(block level),而後按照規則來套用就能夠了。
Bootstrap有不少漂亮的功能,可是我只想演示如下如何在SASS中使用guid class.
在bootstrap中,咱們有下面一些@mixins來建立一個grid系統:
container-fixed()
make-row()
make-xs-column()
make-xs-column-offset()
make-xs-column-push()
make-xs-column-pull()
make-sm-column-offset()
make-sm-column-push()
make-sm-column-pull()
make-md-column-offset()
make-md-column-push()
make-md-column-pull()
make-lg-column-offset()
make-lg-column-push()
make-lg-column-pull()
clearfix()
這樣咱們能夠像下面的代碼同樣來作設計:
section { @include make-row(); article { @include make-xs-column(12); @include make-sm-column(7); @include make-md-column(8); } aside { @include make-xs-column(12); @include make-sm-column(3); @include make-md-column(4); } }
在不使用BEM方法論以前,咱們可能這樣書寫HTML markup:
<section class=」row」> <article class=」col-xs-12 col-sm-7 col-md-8"> Article content </article> <aside class=」col-xs-12 col-sm-3 col-md-4"> Aside content </aside> </section>
而當咱們引入BEM以及借用BOOTSTRAP LESS/SASS的代碼重構後,這樣書寫html markup:
<section> <article> Article content </article> <aside> Aside content </aside> </section>
這樣的HTML更加清晰和易於理解。
咱們再來看看下面兩片代碼:
<div class=」social-links—content」> <div class=」social col-xs-6 col-sm-2 col-md-2"> <div class=」twitter block」> <div class=」centered」> <a href=」http://www.twitter.com" title=」Twitter」> <span class=」sr-only」>twitter</span> <span class=」fa fa-twitter fa-4x」></span> </a> </div> </div> </div> </div>
以及去除bootstrap的預約義class後的代碼:
<div class=」social-links—content」> <div class=」social-links—link js-social-link」> <a class=」link—twitter」 href=」http://www.twitter.com" title=」Twitter」> <span class=」sr-only」>twitter</span> <span class=」fa fa-twitter」></span> </a> </div> </div>
既然咱們的想法是清理html代碼,使得其更加易讀,我刪除了全部的bootstrap grid class,取而代之的是經過@extend,@include直接把grid class插入到css中去:
.social-links—content { @extend .container; .social-link { @include make-xs-column(6); @include make-sm-column(2); } }
而後,我建立一個@mixin來在垂直方向向中間對齊icons:
@mixin vertical-align() { display: block; &:before { content: ‘’; display: inline-block; height: 100%; vertical-align: middle; margin-right: -0.25em; } > * { display: inline-block; vertical-align: middle; width: 98%; } }
這樣我就能夠這樣更新.social-links--content:
.social-links—content { @extend .container; .social-link { @include make-xs-column(6); @include make-sm-column(2); a { @include vertical-align(); } } }
從而將HTML中的div.block和div.centered刪除,也就是從下面的HTML:
<div class=」social col-xs-6 col-sm-2 col-md-2"> <div class=」twitter block」> <div class=」centered」> <a href=」http://www.twitter.com" title=」Twitter」> <span class=」sr-only」>twitter</span> <span class=」fa fa-twitter fa-4x」></span> </a> </div> </div> </div>
變成了下面的BEM風格的代碼:
<div class=」social-links—link js-social-link」> <a class=」link—twitter」 href=」http://www.twitter.com" title=」Twitter」> <span class=」sr-only」>twitter</span> <span class=」fa fa-twitter」></span> </a> </div>
在css開發中,咱們很是喜歡使用nested方式來組織css元素,由於這種方式咱們能夠清晰地看到元素間的層次關係(儘管嚴格使用BEM命名方式也能夠看出來),可是若是通常性地嵌套,則輸出的css爲後代選擇器,一種可行的方法是使用&特殊字符(SASS中使用
@at-root #{&}__element
.btn{ width: 100px; &__icon{ //能夠看到icon做爲btn block的一個元素 color: blue; &--big{ //能夠看到.btn__icon--big做爲btn block下面的icon元素的一個modifier font-size: 20px; } } &--primary{ //能夠看到.btn--primary做爲btn block的modifier background-color: blue; } } 上面的LESS代碼將按照BEM模式的組織方式生成出來的CSS代碼以下: .btn{width:100px} .btn__icon{color:#00f} .btn__icon--big{font-size:20px} .btn--primary{background-color:#00f}
http://www.smashingmagazine.com/2014/07/bem-methodology-for-small-projects/
http://www.smashingmagazine.com/2013/02/the-history-of-the-bem-methodology/