Skip to content

Instantly share code, notes, and snippets.

@danielguillan
Created June 18, 2014 07:23
Show Gist options
  • Save danielguillan/33f4f92cc079148900ec to your computer and use it in GitHub Desktop.
Save danielguillan/33f4f92cc079148900ec to your computer and use it in GitHub Desktop.
Generated by SassMeister.com.
// ----
// Sass (v3.3.7)
// Compass (v1.0.0.alpha.18)
// ----
// =============================================================================
// Mixin-driven BEM definitions
//
// I still don't know whether i like this idea or not.
//
// Conceptually, it looks good:
// — A consitent way of defining BEM objects
// — Element and modifier syntax independence
// — Prevents block duplication
// — Prevents errors in class names (they're all dynamically generated)
// — Better code output (it encourages the use of extends)
//
// But it also looks verbose:
// — It might not be as easy to read as plain class names
//
// =============================================================================
$bem: () !global;
$bem-element-separator: '__' !default;
$bem-modifier-separator: '--' !default;
$bem-modifier-extends: false !default; // not working yet
@function already-defined($list, $target) {
@each $item in $list {
@if $item == $target {
@return true;
}
}
@return false;
}
@function block-already-defined($block) {
@each $item in $bem {
@if map-get($item, block) == $block {
@return true;
}
}
@return false;
}
@mixin block($block) {
@if block-already-defined($block) {
@warn 'Block `#{$block} has already been defined.';
} @else {
$bem: append($bem, (block: $block, elements: (), block-modifiers: (), element-modifiers: ()));
.#{$block} {
@content;
}
}
}
@mixin element($element) {
$current: nth($bem, length($bem));
$current-elements: map-get($current, elements);
@if already-defined($current-elements, $element) {
@warn 'Element `#{$element}` already exists.';
} @else {
$new-elements: append($current-elements, $element, comma);
$bem: set-nth($bem, length($bem), map-merge($current, (elements: $new-elements)));
@at-root &#{$bem-element-separator}#{$element} {
@content
}
}
}
@mixin modifier($modifier, $modifies-block: false) {
$current: nth($bem, length($bem));
$current-block: map-get($current, block);
$current-block-modifiers: map-get($current, block-modifiers);
$current-element-modifiers: map-get($current, element-modifiers);
// Check if $modifier is not within the Block
// If it's within the block, ignore $modifies-block and modifie the block
// warn the use?
@if $modifies-block {
@if not already-defined($current-block-modifiers, $modifier) {
$new-block-modifiers: append($current-block-modifiers, $modifier, comma);
$bem: set-nth($bem, length($bem), map-merge($current, (block-modifiers: $new-block-modifiers)));
}
@at-root .#{map-get(nth($bem, length($bem)),block)}#{$bem-modifier-separator}#{$modifier} & {
@if ($bem-modifier-extends) {
@extend .#{map-get(nth($bem, length($bem)),block)};
}
@content;
}
} @else {
// We can't currently get the current element without Sassscript access to `&`
//@if already-defined($current-element-modifiers, $modifier) {
//$current-element: '&';
//@warn 'Modifier `#{$modifier}` already exists for element `#{$current-element}`';
//} @else {
$new-element-modifiers: append($current-element-modifiers, $modifier, comma);
$bem: set-nth($bem, length($bem), map-merge($current, (element-modifiers: $new-element-modifiers)));
@at-root &#{$bem-modifier-separator}#{$modifier} {
@content
//}
}
}
}
@include block('flag') {
display: table;
width: 100%;
@at-root %flag-items-display {
display: table-cell;
vertical-align: middle;
}
@at-root %align-top { vertical-align: top; }
@at-root %align-bottom { vertical-align: bottom; }
@include element('image') {
@extend %flag-items-display;
padding-right: 10px;
> img {
display: block;
max-width: none;
}
@include modifier('rev') {
padding-right: 0;
padding-left: 10px;
}
@include modifier('top', $modifies-block: true) {
@extend %align-top;
}
@include modifier('bottom', $modifies-block: true) {
@extend %align-bottom;
}
}
@include element('body') {
@extend %flag-items-display;
width: 100%;
@include modifier('top', true) {
@extend %align-top;
}
@include modifier('bottom', true) {
@extend %align-bottom;
}
}
}
.debug {
bem: inspect($bem);
}
.flag {
display: table;
width: 100%;
}
.flag__image, .flag__body {
display: table-cell;
vertical-align: middle;
}
.flag--top .flag__image, .flag--top .flag__body {
vertical-align: top;
}
.flag--bottom .flag__image, .flag--bottom .flag__body {
vertical-align: bottom;
}
.flag__image {
padding-right: 10px;
}
.flag__image > img {
display: block;
max-width: none;
}
.flag__image--rev {
padding-right: 0;
padding-left: 10px;
}
.flag__body {
width: 100%;
}
.debug {
bem: (block: "flag", elements: ("image", "body"), block-modifiers: ("top", "bottom"), element-modifiers: (("rev",)));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment