BEMerald
Pure-sass functions and mixins to make writing BEM a piece of cake. Keeps things simple and handles tricky cases gracefully.
tl;dr
@include Block(notification) {
border: 1px solid #ccc;
padding: 20px;
@include Elem(link) {
float: right;
}
@include Mod(error) {
border-color: red;
}
}
@include B(myblock) {
background: white;
@include E(subelem) {
color: blue;
}
&:hover {
text-decoration: underline;
@include E(subelem) {
color: green;
}
}
@include M(mymod) {
background: green;
@include E(subelem) {
color: green;
}
&:hover {
font-weight: bold;
@include E(subelem) {
color: red;
}
}
}
}
Installation
Right now you have 2 options:
- Copy/paste the
bemerald.scss
file (it's all one self-contained file) into your project
- Install via
npm install bemerald
and configure your builder to point to the node_modules
folder
TODO: Provide easier installation & plugins for common build tools
Usage
in order of most commonly used...
Mixins
The build-in mixins allow you to write your SCSS in a nested way that feels very natural, but still get flat root-level selectors, as per BEM methodology.
@include Block($block) { ... }
Simply unrolls into a class-selector. Main purpose of using this mixin is to clearly denote the start of a BEM block.
@include Block(notification) {
position: relative;
border: 1px solid #ccc;
padding: 10px;
}
@include B(notification) { ... }
@include Mod($mod) { ... }
Unrolls into a BEM block-modifier selector.
May be either:
- String: Simple modifier string.
mod
results in .block--mod
- Map: Modifier string with value.
(mod: value)
results in .block--mod-value
Notes:
- This mixin does not generate element-modifiers. Use
Elem(elem, $mod:mod)
.
- Nesting a Mod inside a pseudo-selector is not supported, because what that should mean isn't clear.
@include Block(notification) {
@include Mod(error) {
background: rgba(red, 0.15);
border-color: red;
}
@include Mod((theme: growl)) {
top: 0;
right: 0;
width: 200px;
height: auto;
}
@include Mod((theme: bar)) {
bottom: 0;
left: 0;
width: 100%;
height: 200px;
}
}
@include M(error) { ... }
@include Elem($elem-name, $mod:null)
Unrolls into a proper BEM element selector, depending on the context:
- Inside just a block, yields a root-level
.block__elem
- Inside a mod or pseudo-selector, yields a nested
.block--mod .block__elem
If $mod
is included, it is appended to the block selector, like .block__elem--mod
. Multiple $mod
s are not supported.
@include Block(notification) {
@include Elem(dismiss-btn) {
position: absolute;
right: 0;
font-weight: bold;
}
@include Elem(dismiss-btn, $mod:on-left) {
left: 0;
right: auto;
}
@include Mod(error) {
@include Elem(dismiss-btn) {
display: none;
}
}
&:hover {
@include Elem(dismiss-btn) {
transform: scale(1.1);
}
}
}
@include E(dismiss-btn, $m:on-left) { ... }
@include BEM($block, $elem:null, $mods:null)
Unrolls into a full BEM selector. See the bem-selector
documentation for parameter details.
@include BEM(notification, $mod:error, $elem:dismiss-btn) {
color: red;
}
Functions
bem-selector($block, $elem:null, $mods:null)
Generates a full BEM selector.
-
$block
: Required. A string block name.
-
$elem
: Optional. A sub-element name. If $mod
is not present, it is joined with $block
. If $mod
is present, it is nested under $block--$mod
May be either:
- String: Simple element name. Results in
.block__elem
- List: Pair like
($elem-name, $elem-mod)
Applies the element-modifier to the subelement. Multiple elem-mods are not supported. Same types as $mod
.
-
$mod
: Optional. A block modifier. May be either:
- String: Simple modifier string. Results in
.block--mod
- Map: ($modifier-name: $modifier-value). Results in
.block--mod-val
-
$mods
: Optional. List. Allows generating selectors for multiple mods at once. Each element of the list should be one of the allowed type for $mod
$s: bem-selector(block);
$s: bem-selector(block, $e:elem);
$s: bem-selector(block, $e:(elem,emod);
$s: bem-selector(block, $m:mod);
$s: bem-selector(block, $m:(mod:val));
$s: bem-selector(block, $m:mod, $e:elem);
$s: bem-selector(block, $m:(mod-a,(mod-b:bval)), $e:elem);
You could use it like...
#{bem-selector(block, $e:elem, $m:mod)} {
}
Shorthand Aliases
The provided mixins come with "shorthand aliases" so you can save some typing.
@include Block(b) { ... }
@include B(b) { ... }
@include Elem(e, $mod:m) { ... }
@include E(e, $m:m) { ... }
@include Mod(m) { ... }
@include M(m) { ... }
Development
One-time setup
npm install; npm install -g mocha;
Run tests
npm test
Runs tests located in /test
With love to...
- Sass in general (duh - sass rocks)
- libsass specifically (speed rocks)
- true (tests rock)
- SassMeister (instant feedback rocks, too)
- You (also rock)
With love from...
Rafflecopter
License
Released under MIT license, same as Sass.
TODO
- Provide easier installation & plugins for common build tools
- test all functions. Right now at least
bem--extract-block
needs tests.
- try to test mixins. Might be tricky since they use
@at-root
- automated test in various sass implementations?