BEM,SASS,LESS,bootstrap:如何有效地將這些方法,工具和框架聰明地整合?

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

Cleaning up css classes

如今已經不多使用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. 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/

相關文章
相關標籤/搜索