Matching multiple BEM modifiers in Sass
Asked Answered
P

3

17

I am using BEM, and have an element with multiple modifiers:

<div class="block__element block__element--m1 block__element--m2"></div>

I'm using SCSS and taking advantage of it to write nested rules compatible with BEM. If I want to write a rule where an element (like the above) has both the m1 and m2 modifier, is there a way to write that compatible with the way I'm currently writing them? This is the kind of syntax I'm after, but results in a syntax error:

.block {
    display: block;

    &__element {
        display: inline;

        &--m1 {
            background-color: red;
        }

        &--m2 {
            background-color: green;
        }

        // Syntax error
        &--m1&--m2 {
            background-color: yellow;
        }
    }
}

I can think of ways around this by using attribute selectors, but is there a neater way?

For the record, the compiled attribute selector should be:

.block__element--m1.block__element--m2
Pasho answered 5/12, 2017 at 11:44 Comment(0)
P
33

@3rdthemagical's answer did give me some inspiration for a better solution. Sass simply doesn't like & appearing after the beginning of the selector, but it doesn't mind it wrapped in #{}:

.block {
    display: block;

    &__element {
        display: inline;

        &--m1 {
            background-color: red;
        }

        &--m2 {
            background-color: green;
        }

        // Correct!
        &--m1#{&}--m2 {
            background-color: yellow;
        }
    }
}
Pasho answered 5/12, 2017 at 12:43 Comment(3)
Nice solution (if a little confusing to read). Thanks for pointing out this handy workaroundSilique
Does not work when you have to put something inside that element with few modifiers. .a { &--m1#{&}--m2 .b { ... } } transpiles into .a .a--m1.a--m2 .b { ... }Scientism
cleverness level 🔟!‎Antitragus
P
1

Store selector names in variables. Sassmeister demo.

.block {
  $module: ".block";

  &__element {
    $this: "#{$module}__element";

    &--m1#{$this}--m2 {
        background-color: yellow;
    }
  }
}

Generated css:

.block__element--m1.block__element--m2 {
  background-color: yellow;
}
Photothermic answered 5/12, 2017 at 12:32 Comment(3)
I was hoping Sass would provide better solutions than this—having to store the selectors in variables as well means I'm having to repeat myself, and Sass's biggest selling point for me is that it helps me avoid just that!Pasho
You did give me inspiration for a correct answer, however! https://mcmap.net/q/694532/-matching-multiple-bem-modifiers-in-sassPasho
You can avoid repeating yourself using the & operator, which as discussed above just inserts the text of the selector so far: .block { $module: &; } will be equivalent to .block { $module: ".block"; }Archiplasm
S
0

I realize it's an old question, but here's a modern solution:


.block {
    display: block;

    &__element {
        display: inline;

        &--m1 {
            background-color: red;
        }

        &--m2 {
            background-color: green;
        }

        &--m1:is(&--m2) {
            background-color: yellow;
        }
    }
}

Staging answered 9/7 at 19:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.