Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to structure BEM modifiers with nested elements in SASS

Tags:

html

css

sass

bem

SASS + BEM is pretty much a match made in heaven most of the time, but a common struggle of mine is understand how to best define BEM modifiers on an element that affects it's child elements while using SASS parent selectors.

I have the following component defined in SASS using BEM style syntax:

.card {
  background-color: #FFF;

  &__value {
    font-size: 2em;
    color: #000;
  }
}

This works well because of SASS's parent selector. It keeps relevant code organized and self-contained.

But when I need to add a modifier that alters a child element using a parent selector, the idea quickly falls apart:

.card {
  padding: 2em;

  &__value {
    font-size: 1.5em;
    color: #000;
  }

  &--big {
    padding: 2.5em;

    &__value {          // Is this going to work?
      font-size: 3em;
    }
  }
}

Nope. It generates this:

.card {
  padding: 2em;
}
.card__value {
  font-size: 1.5em;
  color: #000;
}
.card--big {
  padding: 2.5em;
}
.card--big__value {  // Wrong
  font-size: 3em;
}

It would make more sense to somehow get this selector:

.card--big .card__value {
  font-size: 3em;
}

The reason for this, is so you can simply add a modifier to the top level element and have it affect any or all of the child elements.

I've tried a couple approaches:

Use two structures

.card {
  padding: 2em;

  &__value {
    font-size: 1.5em;
    color: #000;
  }
}

.card--big {
  padding: 2.5em;

  &__value {
    font-size: 3em;
  }
}

This works (especially in this simplified demonstration) but in a more complicated set of components with many modifiers this can be a potential pain to maintain and keep bug free. Also, it would nice to continue to use SASS parent selectors if possible.

Use a variable for the element

.card {
  $component: &;  // Set the variable here

  padding: 2em;

  &__value {
    font-size: 1.5em;
    color: #000;
  }

  &--big {
    padding: 2.5em;

    #{$component}__value {  // Use it here
      font-size: 3em;
    }
  }
}

This works well. But it seems kind of silly to have to define the element as a variable. Maybe it's the only real way to do this... I'm not sure. Are there better options to how to structure this?

like image 753
Jake Wilson Avatar asked Jun 09 '17 06:06

Jake Wilson


People also ask

What are the nested rules in SASS?

Description. Nesting is combining of different logic structures. Using SASS, we can combine multiple CSS rules within one another. If you are using multiple selectors, then you can use one selector inside another to create compound selectors.

How does nesting work in SASS?

Nesting is a shortcut to creating CSS rules. Nesting in SASS works as selector of multiple CSS and combine them within one another instead of writing different CSS lines just to be precise about the style that we want to add to an element, we just nest it up.

What is SASS selector nesting?

Nesting permalinkNestingRather than repeating the same selectors over and over again, you can write one style rules inside another. Sass will automatically combine the outer rule's selector with the inner rule's.


2 Answers

Why not just do this?

.card {
  padding: 2em;

  &__value {
    font-size: 1.5em;
    color: #000;
  }

  &--big {
    padding: 2.5em;
  }

  &--big &__value {  
    font-size: 3em;
  }
}
like image 57
Wouter G. Avatar answered Sep 21 '22 05:09

Wouter G.


You can split up the modifiers in a different structure, but nested within the .card selector, like this:

.card {
  padding: 2em;

  &__value {
    font-size: 1.5em;
    color: #000;
  }

  &--big {
    padding: 2.5em;
  }

  &--big &__value {
    padding: 2.5em;
  }
}

Which will in turn produce this:

.card {
  padding: 2em;
}
.card__value {
  font-size: 1.5em;
  color: #000;
}
.card--big {
  padding: 2.5em;
}
.card--big .card__value {
  padding: 2.5em;
}

I think this is an almost perfect way, although its not perfectly nested I hope this was a help!

like image 30
David Genger Avatar answered Sep 19 '22 05:09

David Genger