1
votes

How does one handle making "variation classes" in Sass? Example:

.bookshelf {
    color: brown;
    height: 100px;

    .panel {
        trimmed: no;
        height: 10px;
    }

    .door {
        height: 100px;

        .knob {
            shape: circle;
            height: 10px;
        }
    }
}

You want to make a .bookshelf.small variation. Is there a way to write the variation code inside the main element using mixins or something that would "bubble up" the data?

.bookshelf {
    color: brown;
    height: 100px;
    @include small-version {
        height: 50px;
    }

    .panel {
        trimmed: no;
        height: 10px;
        @include small-version {
            height: 5px;
        }
    }

    .door {
        height: 100px;
        @include small-version {
            height: 50px;
        }

        .knob {
            shape: circle;
            height: 10px;
            @include small-version {
                height: 5px;
            }
        }
    }
}

And the output of the mixin would be

.bookshelf.small {
    height: 50px;

    .panel {
        height: 5px;
    }

    .door {
        height: 50px;

        .knob {
            height: 5px;
        }
}

Several things looked promising, such as the @at-root function and @content function, but neither would work for this scenario. I know if I write @media settings, they will bubble up. But I do not want this tied to a media query, I want this tied to a specific class (if .bookshelf also has the class small, apply these rules).

2
One way this could be solved would be to use & after the "variation" class name, but only if a way to concat them could be found. So you would just write .small & { /**/ } where the theme specific rules need to be. But that would produce .small .bookshelf instead of .small.bookshelf if a way to concat them isn't available.Ayub

2 Answers

1
votes

There is a small hack about it. But you should work with it really carefully. And it's not so good as you ask.

First of all, it prepends theme class to selector, so you can't use any element selectors. There is actually lot of selector helpers in docs but i didn't found any that could help with real parsing selector string.

Second it's not grouping out selectors. It inserts rules right where mixin were included. But it generates higher priority rules for your styles, so it could be a half a way solution.

You can dig for postcss parser or any other file post processing tool that could help you to separate your styles in a different files.

@mixin small-version {
  @at-root .small#{&} {
    @content;
  }
}

.bookshelf {
  color: brown;
  height: 100px;
  @include small-version {
    height: 60px;
  }

  .panel {
    trimmed: no;
    height: 10px;

    @include small-version {
      height: 5px;
    }
  }

  .door {
    height: 100px;

    .knob {
      shape: circle;
      height: 10px;
    }
  }
}

Gist link

0
votes

You can qualify a selector by putting & to the right of the intended parent of the selector. Wrapping it in #{} allows you to place it directly beside that parent.

The @at-root rule causes everything proceeding it to be emitted at the root instead of using regular nesting.

If you use both, you can achieve what you are looking for.


.flashlight {
    .light {
        background: yellow;

        @at-root .dead-battery#{&} {
            background: transparent;
        }

        .daytime &{
            background: transparent;
        }
    }
}

This would compile to:

.flashlight .light {
  background: yellow;
}
.dead-battery.flashlight .light {
  background: transparent;
}
.daytime .flashlight .light {
  background: transparent;
}