Search code examples
csssassmixins

Produce whitespace-free CSS string with SASS @while loop


I'm attempting to write a mixin that repeats a string as part of a selector. My desired output is very whitespace sensitive, but I can't find a way of making SASS compile without introducing said whitespace.

The desired output would be:

body:nth-child(n):nth-child(n){
  background: blue;
}

body:nth-child(n){
  background: green;
}

body {
  background: red;
}

And I would like to achieve it using this invocation:

body {
  @include increase-specificity( 2 ){
    background: blue;
  }

  @include increase-specificity{
    background: green;
  }

  background: red;
}

The problem is that the :nth-child(n) string can't accept any whitespace after the current selector (&), or between repetitions, without changing the functional CSS afterwards – and I can't find a way of writing a mixin that fulfils this without causing SASS errors.

This is how I've tried to express the mixin:

@mixin increase-specificity( $depth: 1 ){
  &@while($depth > 0){#{'nth-child(n)'}$depth: $depth-1}{
    @content;
  }
}

And here's a Codepen to show it breaking.

My problems so far are:

  • SASS won't tolerate the @while loop immediately following & (&@while{…), but I can't think of any other way to avoid whitespace between the compiled strings.
  • Similarly, I can't find a way of writing a functonal @while loop without being liberal with whitespace: the current syntax falls over when it reaches the end of the the interpolator (#{…}) (don't know why), but removing interpolation causes it to trip up trying to interpret nth-child's parens.

Solution

  • There's so much going on wrong in your code (bad logic, missing whitespace, mismatched brackets, etc.), it's not worth the effort to try and explain why it doesn't work.

    @mixin increase-specificity( $depth: 1 ) {
      $sel: '';
      @while($depth > 0) {
        $sel: $sel + ':nth-child(n)';
        $depth: $depth - 1;
      }
      &#{$sel} {
        @content;
      }
    }
    
    body {
        @include increase-specificity( 2 ){
            background: blue;
        }
    
        @include increase-specificity{
            background: green;
        }
    
        background: red;
    }