Using BEM + Sass parent selectors to target child elements of modifiers without repeating class names

2.8k views Asked by At

I'm using sass and I use the ampersand with BEM to repeat the parent selector, eg -

.c-block {
 background:red;
 &__element {font-size:14px;}
 &--modifier {background:blue;}
}

This outputs -

.c-block {
  background: red;
}
.c-block__element {
  font-size: 14px;
}
.c-block--modifier {
  background: blue;
}

Which makes future updates to the class name nice and easy - change it in one place and sorted!

Now things get more complicated with modifiers and targeting their children:

.c-block {
  background:red;
  &__element {font-size:14px;}
  &--modifier {background:blue;
    .c-block__element {font-size:20px;}     
  }
}

Note how I've had to repeat the class name '.c-block'. Is there any way to avoid this? I only want to have one class name declaration which is referenced down my styles and changed easily in one place.

Is using variables the only way to avoid class name repetition? eg -

.c-block {
  $class: c-block;

  background:red;
  &__element {font-size:14px;}
  &--modifier {background:blue;
    & .#{$class}__element  {font-size:20px;}
    // the above line = .c-block--modifier .c-block__element
  }
}

I keep thinking there must be some better sass+BEM way of doing it rather than using variables.

1

There are 1 answers

2
Neelam Khan On

As someone who uses BEM with SASS, your question made me curious and I found the following article (on CSS tricks) after a quick google, here is a link to it. Instead of using variables, we can create mixins to help achieve what you want, like so:

/// Block Element
/// @access public
/// @param {String} $element - Element's name
@mixin element($element) {
    &__#{$element} {
        @content;
    }
}

/// Block Modifier
/// @access public
/// @param {String} $modifier - Modifier's name
@mixin modifier($modifier) {
    &--#{$modifier} {
        @content;
    }
}

You can then output your SASS like so:

.block {
    /* CSS declarations for `.block` */

    @include element(element) {
        /* CSS declarations for `.block__element` */
    }

    @include modifier(modifier) {
        /* CSS declarations for `.block--modifier` */

        @include element(element) {
            /* CSS declarations for `.block--modifier__element` */
        }
    }
}

Hope this helps in some way!