Search code examples
sassbem

Sass BEM: avoid modifier duplication when element is inside a modifier


Can I somehow refactor the following code snippet to get rid of double modifier declaration?

.block {
  &__element {
    rule: value;
  }
  &--modifier {
    rule: value;
  }
  &--modifier & {
    &__element {
      rule: value;
    }
  }
}

Output wanted:

.block {
   property: value;
}
.block--modifier {
  property: value;
}
.block--modifier .block__element {
  property: value;
}

Solution

  • Nesting elements inside modifiers is a known issue. There are a lot of workarounds.

    Variable way

    Store the block element in a variable.

    And use it interpolated when creating a element inside a modifier.

    .block {
      $block: &;
    
      &__element {
        property: value;
      }
    
      &--modifier {
        property: value;
        #{$block}__element {
          property: value;
        }
      }
    }
    

    See output below.

    Function way

    1. Create a function that returns the block element.

    It'll get the parent selector and cut the word before -- (which is the block). Looks hacky, but it's the simplest way to go.

    @function block() {
      $selector: str-slice(inspect(&), 2, -2);
      $index: str-index($selector, '--') - 1;
      @return str-slice($selector, 0, $index);
    }
    

    2. Use the function interpolated.

    Which will return the name of the block so you don't have to repeat it.

    .block {
      property: value;
    
       &--modifier {
         property: value;
         #{block()}__element {
           property: value;
         }
       }
    }
    

    See output below.

    Both ways will output to:

    .block {
      property: value;
    }
    
    .block--modifier {
      property: value;
    }
    
    .block--modifier .block__element {
      property: value;
    }