Search code examples
csssassbem

How to avoid repeating the parent classname in BEM cascade?


Example code (I know what it can be rewritten to avoid cascade, but I write it as example. This code is't real problem, what I can resolve in another way, it's just illustration):

.b-list {  
  //…

  &__item {
    //…
  }

  &__link {
    height: 4px;
    //…

    @at-root .b-list__item.-active & {
      height: 12px;       
    }     
  }
}

It is compiled to:

.b-list__link {
  height: 4px;
}

.b-list__item.-active .b-list__link {
  height: 12px;
}

I would like to change a selector @at-root .b-list__item.-active &
to something like @at-root &__item.-active & {…}
to avoid repeating the parent classname, but it doesn't work at Sass:

This code doesn't work:

.b-list {  
  //…

  &__item {
    //…
  }

  &__link {
    height: 4px;
    //…

    @at-root &__item.-active & {
      height: 12px;       
    }     
  }
}

So, there is a way to do what I want?


Solution

  • There are ways of acheiving the code you are looking for without an @at-root style function. However, as that was the original question the following should do the trick.

    You can apply & to a variable and escape it as part of the class name later on through the nesting, as follows:

    .b-list {
        $rootParent: &;
        &__link {
            height: 4px;
    
            #{$rootParent}__item.-active & {
                height: 12px;
            }
        }
    }
    

    Seems absolutely crazy but it works!

    If you were looking to recreate the above in a more standardised way, I would definitely recommend the following:

    .b-list {
        &__link {
            height: 4px;
        }
    
        &__item.-active &__link {
            height: 12px;
        }
    }
    

    It's also worth having a read through http://sass-guidelin.es/#selector-nesting, notably the section on BEM naming with the & current selector reference which states:

    While it might be anecdotal, generating new selectors from the current selector reference (&) makes those selectors unsearchable in the codebase since they do not exist per se.