Skip to content

Instantly share code, notes, and snippets.

@evenicoulddoit
Created November 26, 2015 13:50
Show Gist options
  • Save evenicoulddoit/18cb9da280636c2db4b5 to your computer and use it in GitHub Desktop.
Save evenicoulddoit/18cb9da280636c2db4b5 to your computer and use it in GitHub Desktop.
BEM and Sass
/**
* BEM Helper methods. Inspired by http://bit.ly/1QqAOhR.
* Provides mixins @block, @element and @modifier.
* Requires SassyLists and SassyStrings.
*/
$bem-element-separator: '__';
$bem-modifier-separator: '--';
/**
* Return a list of all of the rules within the selector
*/
@function rules($selector) {
@return str-explode(str-trim(stringify($selector)), " ");
}
/**
* Return whether the last rule in the given selector is a modifier
*/
@function lastRuleIsModifier($selector) {
$lastRule: sl-last(rules($selector));
@if(str-index($lastRule, $bem-modifier-separator)) {
@return true;
}
@else {
@return false;
}
}
/**
* Return the last rule without the modifier
*/
@function lastRuleWithoutModifier($selector) {
$lastRule: sl-last(rules($selector));
@return sl-first(str-explode($lastRule, $bem-modifier-separator));
}
/**
* For each of the given elements, create a combined rule, applying the given
* prefix.
*/
@function combinedRule($prefix, $elements) {
$rules: ();
@each $element in $elements {
$rules: append($rules, unquote($prefix +$element), 'comma');
}
@return $rules;
}
@mixin block($block) {
.#{$block} {
@content;
}
}
/**
* Append the given elements to the previous selector.
* If the last rule was a modifier start a new rule from the point of the
* modifier.
*
* Example:
* [In]: .foo__bar--zulu {
* @include element(alpha) { font-weight: 700; }
* }
* [Out]: .foo__bar--zulu .foo__bar__alpha { font-weight: 700; }
*/
@mixin element($elements...) {
$selector: stringify(&);
@if(lastRuleIsModifier($selector)) {
$withoutModifier: lastRuleWithoutModifier($selector);
@at-root {
#{$selector} {
#{combinedRule($withoutModifier + $bem-element-separator, $elements)} {
@content;
}
}
}
}
@else {
@at-root {
#{combinedRule($selector + $bem-element-separator, $elements)} {
@content;
}
}
}
}
@mixin modifier($modifier) {
@at-root {
#{&}#{$bem-modifier-separator + $modifier} {
@content;
}
}
}
/**
* Return an adjacent selector composed of the last rule followed by itself.
*/
@mixin siblingSelf() {
$lastRule: sl-last(rules(&));
& + #{$lastRule} {
@content;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment