Sass: adjust-font-sizeミックスイン

ビューポートの幅に合わせてフォントサイズを変更するCSSを、コッぺッするのをやめSassのミックスインにした。あんまり見ない感じのミックスインになったのでメモがてらエントリーに。こうなるともうCSSじゃないどころかSCSSとしてもとても読みづらいものになってきていて、ダメなミックスインの例な気がしないでもない。

$safe-for-content: 4.5em;
$safe-for-full: 66em;

@mixin adjust-font-size($sizes) {
  @each $size in $sizes {
    $ratio: $size / 16px;
    $feature: min-width;
    $value: $safe-for-full * $ratio * $ratio;

    @if ($ratio < 1) {
      $feature: max-width;
      $value: $safe-for-content * $ratio * $ratio;
    }

    @media screen and ($feature: $value) {
      font-size: percentage($ratio);
    }
  }
}

html {
  font-size: 100%;

  @include adjust-font-size((14px, 18px, 21px, 24px, 27px, 30px));
}

引数で使うフォントサイズをpx単位でリスト指定し、ミックスイン側で16pxからの比率(pxpxで割るとユニットレスにちゃんとなる)を基準に切り替えていく@mediaルールを吐くというもの。ミックスインの引数でリストを使いたい場合は括弧を使ってまとめる。リストにしておくとミックスインでは@eachルールでサクッと参照できるので繰り返し処理に強く、覚えておくとベンダー拡なんとかとかなんとか張プリフィックスとかフォールバック処理を書く時とかに便利だったりする。

max-widthmin-widthの切り替えは@ifルールでやる。Sassにはスコープはないけど局所変数はあるので、@elseも使って完全に分岐してその内側で変数を定義してしまうと、その外で吐く@mediaルールで参照できなくなる。ここをシンプルにしたいなら最小のフォント・サイズをデフォルトにするとかCSSの工夫が必要になる。そうすると適用された結果は同じでも、CSS自体が少し直観的なものではなくなるので、多少複雑でもCSSの簡明さを優先した方が良いと思う。

Sass 3.2から@mediaルールのクエリー部分でも変数を使えるようになったので、それを使うとこのように普通に書ける。3.2はもうそこそこ安定しているので余程の理由がない限り移行したほうがいいんじゃないかと思う。インタラクティブ・シェルも速くなって普通に使える感じになってるとか、Sassの文法の拡充以外にもいくつか利点ある。

html要素でやってるのはrem単位を見据えてなので、今のところあんまり意味は無い。