https://medium.com/@andersonorui_/bem-sass-and-bootstrap-9f89dc07d20f
Bootstrap是一個“HTML,CSS和Javascript的框架,用於開發responsive,mobile first project";
SASS是一個css擴充套件預編譯工具;
BEM是一個解決css可維護可擴充套件的方法原則
我通常使用LESS,一個原因是Bootstrap本身是Less寫的。注意SASS和LESS有一些區別可能會讓你感覺很奇怪:
變數覆蓋的原則不同: LESS:後面定義的會覆蓋前面的,並且在整個程式碼中都以後面定義的值為準;SASS則是先定義的會先生效直到遇到重新覆蓋定義為止。
注意這個區別對你使用LESS/SASS來開發bootstrap的定製設計時,比如variable.less/sass檔案(也就是所謂bootstrap.theme.less),其位置就很重要了,對於less,則需要你的客製化variable放到後面引入,而對於sass則需要最早引入。
Cleaning up css classes
現在已經很少使用photoshop或者illustrator了,幾乎所有工作從專案開始時就直接在html/css/js中進行,當然有時可能我會使用sketch3來做一下brainstrom或者建立ui elements。也正因為此,我的程式碼越來越亂,以至於不得不重構程式碼。當然這個workflow也是我所喜歡的,因為在專案啟動時我們幾乎不知道我們打算如何去解決問題,我們無法看到所有的patterns,深思熟慮有些浪費時間,所以我往往喜歡在當專案有一個始終一致的模樣時才來做這個工作。這樣可能更有效果。
重構之前我可能有下面的html markup,
<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. Eelement . Modifier
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:
- behavior — JavaScript, CoffeeScript
- appearance — CSS, Stylus, Sass
- templates — BEMHTML, BH, Jade, Handlebars, XSL
- documentation — Markdown, Wiki, XML.
"
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.”
Means of Describing Pages and Templates
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>
BEM TREE
{ 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中。
Independent CSS
從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:不要使用層疊特性!
Naming for independent CSS classes
一種可能的命名方案是:
- 一個block的css class name和他的block name是一致的
- 一個element的css class name由block name+element name組成
<ul class="menu"> <li class="menu__item"> ... </li> <li class="menu__item"> ... </li> </ul>
很有必要將block name包含在一個element的css class name中,因為這將最小化層疊的可能。同時注意使用一致的seperator(這裡使用的是__),這對於允許自動化的工具介入開發流程很有幫助。
當然你可以使用其他的命名方式,我們推薦的方式是:
- Block name: block name is a keyword that makes sence what is a block about. A block name may be composed of serveral words seperated with hyphen(我這裡推薦是blockname由一個或多個單詞直接連線而成): bbbb
- Block prefix: 一個block name通常有一個prefix來幫助指示block的purpose
- b- :比如b-menu-horiz 有實實在在的apperance; b-bbbb
- i- :比如i-menu 這是一個抽象的block它自己並沒有外觀,主要用於實現某種功能而存在,比如它提供了一個功能,被b-menu-horiz block加以使用 i-bbbb
- l- : l-bbbbb 表示一個layout的block
- Element name: 全名稱的element name用於指示這個元素屬於那一個block,比如 b-blockname__elementname,b-menu-horiz__item, b-popup__content bbbb_eeee
- Block modifier: 全名稱的modifier block用於指示它屬於哪個block, 比如b-block-name_modifier-name_modifier-value, b-link_type_pseudo,b-menu-horiz_type_simple,b-popup_direction_up bbbb__mmmm
- Element modifier's name: 全名稱用於指示他屬於哪一個元素(並且哪一個block),b-block-name__element-name_modifier-name_modifer-value,比如b-menu-horiz__item_state_current bbbb_eeee__mmmm-vvvv
Independent templates
從模版引擎的角度來看,block independence意味著:
- blocks and elements必須在input data中描述,blocks(or elements)must have unique "names" to make things like "Menu" should be placed here"expressible in our templates;
- Blocks may appear anywhere in a BEM tree
Modifiers For Elements And Blocks
我們如果需要建立一個和已經存在的一個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; }
Blocks Consistency
一個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:
- Templates(XSL,TT2,Javascript,etc), which turn block declarations into HTML code;
- CSS that describe apperance of the block;
如果一個block有動態的behaviour,我們還需要新增
- 一個javascript implmentation for the block,
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
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更加清晰和易於理解。
SASS
我們再來看看下面兩片程式碼:
<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>
使用LESS 巢狀feature實現BEM命名方法:
在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/