読者です 読者をやめる 読者になる 読者になる

AtCSS: Annotation based CSS Processor

AtCSSという、プリプロセスに必要なメタデータCSSファイルのコメントにアノテーションとして記述し、変換するツールを作った。 開発自体は約3ヶ月前から行っていたが、先日v1.0をリリースしたのでブログで紹介してみる。 ちなみに読み方は「アットシーエスエス」です。

Annotations based CSS Processing

以下がAtCSSのコードの例である。 CSSのコメント内に@で始まるメタデータを仕込み、それを元に変換する。

.base-1 {
  /*
   * @base
   * @constant
   */
  font-size: 12px;
  padding: 8px 16px;
}

.base-2 {
  /*
   * @base
   */
  color: red;
}

/* @start constant */

.class {
  /*
   * @use .base-1
   */
  background-color: green;
}

/* @end constant */

.too-long-and-ugly-selector-name {
  /*
   * @use .base-2
   */
  margin: 10px;
}

ここで使っているアノテーションを説明する。 まず@baseというのは、AtCSSで継承元のルールセットであることを示すためのもので、後に説明する@useを使って継承する。

@constantは、そのルールセットの同一セレクタによる上書きを禁止するもので、この場合だとどこかで.base-1セレクタ名のルールセットを作るとエラーとなる。 これは以前作ったYACPにもある機能だ。 @baseで継承元のルールセットを定義するときに一緒に使うと便利っぽい。

@start constant@end constantは、この間にかかれたコード内(仮にconstantブロックと呼ぼう)でのカスケーディングを禁止するものだ。 上記のコードの場合、.classがそれにあたる。 このconstantブロック内で、.class {}.nested .class {}.children > .class {}と言ったルールセットを定義し、.classが上書き(カスケーディング)するとエラーとなる。

最後に@useだが、これは@baseで定義した継承元のルールセットのプロパティ宣言を継承(再利用)するためのものだ。 この例では、.class.base-1を、.too-long-and-ugly-selector-name.base-2@useしている。 しかし、AtCSSの継承はSass等の@extendとは少し違う。 以下は、上記のコードを変換した結果だ。

.class {
  /*
   * @base
   * @constant
   */
  font-size: 12px;
  padding: 8px 16px;
}

.class {
  /*
   * @use .base-1
   */
  background-color: green;
}

.too-long-and-ugly-selector-name {
  /*
   * @use .base-2
   */
  margin: 10px;
  color: red;
}

まず、.base-1@useした.classだが、これはSassの@extendと同様に継承先のルールセットのセレクタ名を継承元のルールセットのセレクタに付与するかたちでプロパティを継承していることがわかる。 次に.base-2@useした.too-long-and-ugly-selector-nameだが、こちらは継承元である.base-2内のプロパティ宣言が継承先の.too-long-and-ugly-selector-name内に展開されている。

このように、AtCSSでは他のルールセットを継承した際の振る舞いが2通りあり、変換後のファイルサイズが小さい方の選択を自動でおこなっている。 具体的には、

  • 継承先のセレクタ名の文字数が継承元の全プロパティ宣言の文字数よりも多い
  • メディアクエリ内で@useしている

この2つの状況では後者のプロパティ宣言を展開する継承を選択肢、それ以外は前者の@extendと同じ振る舞いの継承となっている。

後者のような継承を、既存のプリプロセッサーでも@mixinを利用することで可能だが、インターフェースを統一したい、開発者が意識せずパフォーマンスの良い選択をさせたい、といった思いから実装した。

なぜアノテーションなのか

わざわざコメントにアノテーションを記述させるかたちにしたのには理由がある。それは、開発時の変換前のコードもブラウザが解釈できるようにしたかったからだ。

また、少し抽象的な話になるが、HTMLとCSSにおいての命名の際、HTML側からは構造やそのコンテンツの性質に対して名前を付け、CSS側からは見た目やデザインの意図に対して名前を付けるのが良いと思っている。 見た目に対して名前を付けている例として、Utility Casses(汎用クラス)と呼ばれるものがある。 簡単に説明すると、以下のような、単一プロパティで定義されたルールセットのことだ。

.font-sm {
  font-size: 10px;
}

.bg-blue {
  background-color: #0089ff;
}

.mgr-10 {
  margin-right: 10px;
}

汎用クラスを使用することで、素早いデザインの微修正が可能となり、インブラウザデザインや開発時のスピードアップを見込める。 しかし、多用するとWebサイトのメンテナンス性が低下する。

この問題を解決するための手段として、Sassの@extendを使って汎用クラスをまとめて意味のある名前にするのが良いと思っている。

%font-sm {
  font-size: 10px;
}

%bg-blue {
  background-color: #0089ff;
}

%mgr-10 {
  margin-right: 10px;
}

.class {
  @extend %font-sm;
  @extend %bg-blue;
  @extend %mgr-10;
}

しかしこのコードには、placeholder(%)セレクタ@extendといった、CSSを拡張した、ブラウザが解釈できない構文が含まれている。 そのため、開発時に%font-smをHTMLのclass属性値にすることはできないし、表示確認のごとにコンパイルする必要がある。

このような理由から、全ての変換のためのメタデータをコメントに記述することで、開発時と本番時で同じCSSで異なる名前を付けるのはどうか、という考えでAtCSSは作られた。

morishitter/atcss

参考サイト