Saasの「@at-root」が正常に効かないパターン

Saasの「@at-root」記法を使うことで、CSSコンパイル時に親クラスの名前を引き継ぎつつムダにネスト(入れ子構造)しなくなります。

@at-root記法サンプル

.class-a {
  width: 100px;
  @at-root {
    #{&}-1 {
      margin: 0;
    }
    #{&}-2 {
      padding: 0;
    }
  }
}

例えば上記のSaas記法の場合、下記のようなCSSが出力されます。

.class-a {width: 100px;}
.class-a-1 {margin: 0;}
.class-a-2 {padding: 0;}

@at-rootで括った中は親クラスにネストせず、#{&}が親クラス名を継承します。

Sassはネストが深くなりがちですが、@at-rootの記法を使うことでムダなネストを減らし、ファイルサイズやブラウザ描画速度の低減に役立ちます。また親クラスの名前を変えれば子クラスの名前も一度に変更されます。

使いこなせれば便利な@at-root記法ですが、思いがけない落とし穴がありました。

@at-rootが効かない例

上記例の「class-a」に加え、全く同じスタイルの「class-b」を追加したいと思い、以下の記述にしました。

.class-a, .class-b {
  width: 100px;
  @at-root {
    #{&}-1 {
      margin: 0;
    }
    #{&}-2 {
      padding: 0;
    }
  }
}

一行目に「class-b」の記述を加えただけですが、実際に出力されたCSSは以下のようなものでした。

.class-a, class-b {width: 100px;}
.class-a, class-b-1 {margin: 0;}
.class-a, class-b-2 {padding: 0;}

違う、そうじゃない。
これでは「class-a」のスタイルが崩れてしまいます。

本来ならこういう出力を期待してました。

.class-a {width: 100px;}
.class-a-1 {margin: 0;}
.class-a-2 {padding: 0;}
.class-b {width: 100px;}
.class-b-1 {margin: 0;}
.class-b-2 {padding: 0;}

結構トリッキーな使い方したとは思いますが、バグか仕様か「@at-root」記法の親クラスを複数設定すると意図しないCSSになってしまうようです。