SCSSでの落とし穴

SassをSCSSで書いていてはまった落とし穴についてのメモ。

プロパティのネスト

h1 {
  font {
    family: "Gabriola", sans-serif;
    size: 400%;
  }
}

とうっかり書いてしまうと、

h1 font {
  family: "Gabriola", sans-serif;
  size: 400%; }

となる。プロパティのネストを使う時はコロンが必要で、他の部分と記述が違うので注意が必要。

h1 {
  font: {
    family: "Gabriola", sans-serif;
    size: 400%;
  }
}

SCSSではこの記述のみがCSSと比較するとかなり特異なので、使わないと決めてしまうのも良さそう。

負の値の計算

$gutter: 20px;

margin: 0 0 0 -$gutter;

だと、

margin: 0 0 -20px;

にコンパイルされるので意図したとおりにならない。

margin: 0 0 0 (- $gutter);

などと括弧でくくる。計算式を書く場合は必ず括弧で括ると習慣づけた方が安全そう(必要ない場合でも)。

負の値の計算 #2

$column: 60px;
$gutter: 20px;

margin: 0 (- $column * 3 + $gutter * 2);

などと、計算結果にマイナス記号を付けるというようなことはできない。

margin: 0 (- $column * 3 - $gutter * 2);

と普通に書く。計算式の括弧もネスト出来るので、

margin: 0 (- ($column * 3 + $gutter * 2));

と面倒がらずにちゃんと書く方がより良いと思う。

ミックスインにカンマを含む文字列を引数として渡せない

@mixin fonts($families) {
  font-family: $families;
}

h1 {
  @include fonts("Lucida Grande", "Lucida Sans Unicode", sans-serif);
}

だと、カンマが引数の区切りとして解釈されるので、

test.scss|18| in `fonts': Mixin fonts takes 1 argument but 3 were passed.

となりコンパイルエラー。エスケープする方法がありそうだけど調べてない。基本的にCSSのプロパティの値としてカンマを使うことはあまり無いので、はまることはあまりなさそう。よくわかっていない時になんでもミックスインにしようとして作った、こういう変で役に立たないミックスインでのみはまる。

$heading: "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", sans-srif;

@mixin fonts($families) {
  font-family: $families;
}

h1 {
  @include fonts($heading);
}

変数経由なら問題はない。

カスケーディングを考慮したセレクタ順

#nav {
  li {
    a {
      color: blue;

      &:hover {
        color: green;
      }
    }

    &.active {
      a {
        color: red;
      }
    }
  }
}

とセレクタのネストを優先させて書くと、

#nav li a {
  color: blue; }
  #nav li a:hover {
    color: green; }
#nav li.active a {
  color: red; }

となるので、#nav li.active aがオンマウスで色が変わらない。a&.activeを入れ替えれば、

#nav li.active a {
  color: red; }
#nav li a {
  color: blue; }
  #nav li a:hover {
    color: green; }

となるので、カスケーディングの規則に従ってちゃんと意図通りになるが、カスケーディングをきちんと理解していないと生成されるCSSがわかりづらい。

#nav li a {
  color: blue; }
#nav li.active a {
  color: red; }
#nav li a:hover {
  color: green; }

という比較的直感的なセレクタの順序(普通にCSSを書く時のセレクタの順序)でCSSを生成するためには、

#nav {
  li {
    a {
      color: blue;
    }

    &.active {
      a {
        color: red;
      }
    }

    a {
      &:hover {
        color: green;
      }
    }
  }
}

と無理やり間に入れるしかないようだ。

追記

ミックスインにはカンマを含む引数を絶対に渡せないというわけではない。例えば以下の様なケースでは問題ない。

@mixin transform($func) {
  -moz-transform: $func;
  -webkit-transform: $func;
  -o-transform: $func;
  -ms-transform: $func;
  transform: $func;
}

.flip-vertical {
  @include transform(matrix(1, 0, 0 , -1, 0, 0));
}

カンマを含んでいるが、これは正常にコンパイルされる。

.flip-vertical {
  -moz-transform: matrix(1, 0, 0, -1, 0, 0);
  -webkit-transform: matrix(1, 0, 0, -1, 0, 0);
  -o-transform: matrix(1, 0, 0, -1, 0, 0);
  -ms-transform: matrix(1, 0, 0, -1, 0, 0);
  transform: matrix(1, 0, 0, -1, 0, 0); }

さっき知った!関係ないけど、このmatrix(1, 0, 0, -1, 0, 0)は対象を上下に反転するもの。180度回転ではない。ショートカット関数は用意されてないので覚えておくと良いかも。CSSも数学できないともうダメっぽい……。せめて行列だけでもちゃんと思い出そう。