22

I'd like to implement something like the BEM model in my Sass library. But I'm struggling to find a clean way to do this.

For example, I'd like to declare a 'base' style for a common element, and then extend it with useful variations:

.container {
  margin: 10%;
  background: #eee;

  &-featured {
    border: 2px solid #999;
  }

}

The problem here is that the generated .container-featured class only contains the border property—Sass doesn't include the margin and background from its 'parent' class.

So you end up having to double up on classes in your markup to get the desired results:

<div class="container container-featured">
  ...
</div>

Is there some way to pull the properties from a parent class down into that modifier class, so you can get the same visual result just referencing the modifier class in your markup?

<div class="container-featured">
  <!-- has margin, background, and border styles via just modifier class -->
</div>

I've tried using mixins to do this, but things get verbose and repetitive very quickly:

@mixins container {
  margin: 10%;
  background: #eee;
}

.container {
  @include container;

  &-featured {
    @include container;
    border: 2px solid #999;
  }

}

Is there a simple, clean way of achieving this with Sass?

markedup
  • 1,247
  • 2
  • 12
  • 21

2 Answers2

32

What you are looking for is the @extend directive. @extend allows you share a set of CSS properties from one selector to another. This means that you would only need to use the container-featured class.

Example

.container {
  margin: 10%;
  background: #eee;

  &-featured {
    @extend .container;
    border: 2px solid #999;
  }
}

compiles to:

.container,
.container-featured {
    margin: 10%;
    background: #eee;
}

.container-featured {
    border: 2px solid #999;
}
Colin Bacon
  • 15,436
  • 7
  • 52
  • 72
  • It's true, and the CSS code won't be enormous. I edit my answer. – Paleo Oct 21 '14 at 11:04
  • The resulting CSS isn't what I was expecting, but the solution remains the same. Thanks very much, this is simple enough to work for me! – markedup Oct 21 '14 at 14:26
  • 1
    So how might one reference a nested selector? ie `container__item--mod` when the less is written as `.container { &__item { &--mod { } } }` Or is there a better way to nest? – Plummer Sep 02 '15 at 21:23
1

You should use mixin in BEM not in Sass!

Mixins are just that - usage of several blocks and/or elements on the same DOM node.

A single DOM node can represent:

  • several blocks b-menu b-head-menu
  • a block and an element of the same block b-menu b-menu__layout
  • a block and an element of another block b-link b-menu__link
  • elements of different blocks b-menu__item b-head-menu__item
  • a block with a modifier and another block b-menu b-menu_layout_horiz b-head-menu
  • several different blocks with modifiers b-menu b-menu_layout_horiz b-head-toolbar b-head-toolbar_theme_black

Read more at: http://bem.github.io/bem-method/html/all.en.html, section Mixin.

Also you can use i-blocks (abstract blocks), so your .container will be .i-container, read more: http://bem.github.io/bem-method/html/all.en.html, section Naming conventions.

And with Sass you can implement i-block as

<div class="container-featured">
  ...
</div>

%i-container {
  // abstract block styles
  margin: 10%;
  background: #eee;
}

.container-featured {
  @extend %i-container;
  border: 2px solid #999;
}

Without Sass, mixin in the BEM are made as follows:

<div class="i-container container-featured">
  ...
</div>

.i-container {
  // abstract block styles
  margin: 10%;
  background: #eee;
}

.container-featured {
  border: 2px solid #999;
}
Ihor Zenich
  • 10,727
  • 3
  • 22
  • 18
  • Other than making the generic container's base declaration a placeholder rather than an ancestor class (which actually seems like a loss of functionality in terms of convenience and reuse), I don't understand what benefit this approach has over Colin's suggestion? – markedup Jan 12 '15 at 16:34
  • @markedup The difference is that the Colin's proposal is just a style inheritance. But my example is how to do it correctly from the point of view of BEM methodology - by the mixin. To make it clear, here is an example without Sass: .i-container { // abstract block styles margin: 10%; background: #eee; } .container-featured { border: 2px solid #999; } – Ihor Zenich Jan 13 '15 at 12:10