BEM — Building 'em modular

Vladimir Grinenko, Yandex

BEM for Ecentia

Vladimir Grinenko
July 8

pain

Vladimir

Agenda

BEM you know

Where pain comes from

Where pain comes from

Where pain comes from

CSS has no scoping

a { /* Affects all the links */
    color: red;
}
ul li a { /* Affects all the links in lists */
    color: green;
}

Specificity conflicts

<div id="test">
    <span>Text</span>
</div>

div#test span { color: green }
span { color: red }
div span { color: blue }

How to overwrite

<div class="sidebar">Left floated sidebar</div>

.sidebar { /* Does it redefine `div.sidebar`?! */
    float: right;
}

body .sidebar { /* Overwrites 'div.sidebar {}' */
    float: left;
}

How to overwrite

.navbar-inverse .navbar-nav>li>a { color: #999; }

#home-menu-container #home-menu li a { color: red; }

body #home-menu ul li a { color: blue !important; }

Non-deterministic matches

#content div div {
    float: left;
}

Removing unused code

100 pages in projects

.person div a {
    color: pink;
}

Is it safe to remove this code?

cure

BEM Methodology

Block

block

Block,        elements

elements

Block,        elements,        modifiers

modifiers

cat_type_red

cat_type_red

cat_state_wet

cat_state_wet

Naming convention

Block__Element_Modifier

Block__Element_Mod_ModValue

Some of BEM principles

Why no ids?

#menu {
    list-style: none;
}

Why no selectors on tags?

#content div div {
    color: red;
}

Why avoiding cascade in CSS? o_O

<ul class="menu">
    <li class="item">Tab 1</li>
    <li class="item">Tab 2</li>
</ul>

.menu .item {
    /* styles for element */
}

Why avoiding cascade in CSS? o_O

<div class="panels">
    <div class="item">
        <ul class="menu">
            <li class="item">Tab 1</li>
            <li class="item">Tab 2</li>
        </ul>
    </div>
</div>

How?

<div class="panels">
    <div class="panels__item">
        <ul class="menu">
            <li class="menu__item">Tab 1</li>
            <li class="menu__item">Tab 2</li>
        </ul>
    </div>
</div>

Why no CSS outside of a block?

<ul class="menu">
    <li class="menu__item current">Tab 2</li>
<ul>

.menu__item.current { /* combined selector */
    background-color: red;
}

Hard to override

.menu__item.current {
    background: white;
}

.menu_dark .menu__item {
    background: black; /* Still white, baby */
}

What we've got so far

BEM we created

Library time!

library/
	block1.css
project/
	blocks/
		block1.css
	project.css
		@import(../library/block1.css);
		@import(blocks/block1.css);

File system

prj/
    blocks/
        header/
            header.css
            header.js
            header.tmpl
            header.svg
            header.md
		

File system

project/
    blocks/
        header/
            _theme/
				header_theme_simple.css
				header_theme_full.css
            __logo/
                header__logo.css
		

BEM tree

<ul class="menu">
    <li class="menu__item">item</li>
    <li class="menu__item menu__item_state_current">item2</li>
</ul>


{
    block: 'menu',
    content: [
        {
            elem: 'item',
            content: 'item1'
        },
        {
            elem: 'item',
            elemMods: { state: 'current' },
            content: 'item2'
        }
    ]
}

BEM tree

Old School

Old school

<div width=120 height=200></div>

Old school

<div width=120 height=200></div>
<div width=120 height=200></div>
<div width=120 height=200></div>

Old school

<div width=120 height=200>
	<div width=40 height=40>
		<div width=34 height=34></div>
	</div>
</div>
<div width=120 height=200></div>

Declarative CSS

.block
{
    width: 120px;
    height: 200px;
}

Declarative CSS

.block
{
    width: 120px;
    height: 200px;
}

.block
{
    height: 220px;
    background: red;
}

Old school

<div class="block" onclick="doSomething()"></div>

Semi-declarative JS

$('.block').doSomething();

Semi-declarative JS

<div class="block"></div>
<div class="another-block"></div>

$('.block').doSomething();

$('.another-block').switchClass('another-block', 'block');

Truly declarative JS made BEM way

BEM.decl('block', {
	onSetMod: {
	    modifier1: {
	        value1: function() {
	            this.onM1V1();
	        },
	        '': function() {
	            this.onRemoveM1();
	        }
	    }
	}
});

Truly declarative JS made BEM way

BEM.decl('block', {
	onSetMod: {
	    modifier1: {
	        value1: function() {
	            this.onM1V1();
	        },
	        '': function() {
	            this.onRemoveM1();
	        }
	    }
	}
});

Truly declarative JS made BEM way

BEM.decl('block', {
	onSetMod: {
	    modifier1: {
	        value1: function() {
	            this.onM1V1();
        ...
});

BEM.decl('block', {
	onSetMod: {
	    modifier1: {
	        value1: function() {
	            this.doSomethingElse();
	    ...
});

Templates

var ctx = { temperature: 42 };

BEM templates

var ctx = { temperature: 42 };
var view = { block: 'weather' };
block('weather')( tag()('ul'), content()({ elem: 'inner', content: ctx.temperature }), elem('inner')( tag()('li') ) );

BEM templates

<ul class="weather"> <li class="weather__inner"> 42 </li> </ul>

Web components

shadow-dom

Web components

<audio controls src="campjs.mp3"></audio>
shadow-dom

BEM blocks

{ block: 'audio', hasControls: true, src: 'campjs.mp3' }
shadow-dom

One BEM to rule 'em all

How will your development process
look like?

How to start?

With methodology

With the platform

that has

bem.info

bem.info/forum

WOW

BEM

Block__Element_Modifier

Links about BEM

Links

Thanks to Varya Stepanova

Fork me on Github