BEM,SASS,LESS,bootstrap:如何有效地将这些方法,工具和框架聪明地整合?

2019年11月20日 阅读数:65
这篇文章主要向大家介绍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/