min-width
を使ったクエリーのみをソートするオプションを追加し、CSS MQPacker v3.1.0をリリースした。sort
オプションを有効にすると、まとめられたクエリーのうちmin-width
が使われるクエリーのみソートされる。
オプションの切り替えに対応するため、新たに引数を渡してインスタンスを作成できるようになった。今までの使われ方を壊さないように実装したので、今までのコードはそのまま動く。
var mqpacker = require('css-mqpacker');
var result = mqpacker({
sort: true
}).pack(css);
console.log(result.css);
ソート機能を有効にするにはsort
オプションをtrue
にしてインスタンスを作成してやる。PostCSSのプロセッサー(プラグイン)として使う場合も同じだ。PostCSSのオプションに混ぜ込むことも可能だが、将来的な安全は保証されていないので推奨しない。なおデフォルトでは無効のため、明示的に有効にしてやる必要がある。
@media (min-width: 2em) {}
@media print {}
@media (min-width: 48px) {}
@media (min-width: 16px) {}
.foo {}
@media (min-width: 48px) {}
@media (max-width: 8px) {}
@media (min-width: 2em) {}
@media (min-width: 16px) {}
例えばこのようにmin-width
クエリーが散在し、それらが複数の単位を用いている上、他の種類のクエリーも混ざっているようなケースを処理してみよう。ありそうもないように思えるが、CSSプリプロセッサーで@media
ルールをネストして書いていると似たような構成にはなりうるはずだ。
.foo {} /* .foo {} */
@media (min-width: 16px) {} /* @media (min-width: 2em) {} */
@media (min-width: 2em) {} /* @media print {} */
@media (min-width: 48px) {} /* @media (min-width: 48px) {} */
@media print {} /* @media (min-width: 16px) {} */
@media (max-width: 8px) {} /* @media (max-width: 8px) {} */
sort
オプションを有効にして処理すると、このように同じメディア・クエリーがまとめられ、後ろに回された上で、min-width
クエリーのみがソートされる。わかりやすいようにsort
オプションを指定しない場合の順序もコメントで併記しておいた。
px
以外の単位はなんとなくpx
単位に変換(フォントの初期設定が16pxでArialとみなして変換を行う)されてソートされるので、複数の単位が混ざっていてもそれなりに機能する。in
やpt
など環境に強く依存する単位はサポートしていないので、無視されソートされることはない。min-width
以外にprint
メディア・タイプなども含め特別視することはないので、それらは今まで通り出現順のまままとめられるというわけだ。
現状ではmin-width
のみ、せいぜいそれに加えてprint
のみを使って書くのが主流と考えられるので、大抵は問題なく適切な状態に処理されることと思う。なにかおかしいところが見つけたら是非報告して欲しい
sort
オプションには直接関数も指定することができる。こちらを使うと自由にソートすることができる。
var result = mqpacker({
sort: function (a, b) {
return a.localeCompare(b);
}
}).pack(css);
例えばString#localeCompare
を使うと、雑に文字コード順でソートすることができる。
作成した関数は、完全なクエリーの配列に対するArray#sort
へと渡される。例えばテストにあるsort_ignore-print-queries.css
だと以下のような配列になる。
[
"(min-width: 2em)",
"print and (min-width: 1em)",
"print, (min-width: 3em)",
"(min-width: 1em)"
]
これをちゃんと処理しなければならないので、カンマ区切りの処理やand
区切りの処理も自前で用意する必要がある。min-width
だけでもかなり大変だったので、かなり苦労することと思う。そこそこちゃんとパースした結果を渡すというのも悪くはないと考えていたが、どちらかというとPostCSSというかAST側でやって欲しい機能なので、ツール側で持ってしまうのはやめておいた。
このソート関数の作成は汎用化しようとするとかなり大変な労力を必要とする。特化型で作るのなら簡単だが、その場合はCSS側でソート順を定義してやる方が更に手軽だったりもする。そのためまず出番はないことと思うがどうしてもmax-width
で書きたいという場合などには役に立つかもしれない。
ソートする機能の実装はとにかく面倒臭かった。print and (min-width: 1px)
は無視して良さそうだが、print, (min-width: 1px)
は無視するべきではなさそうだ、など、普段まともにCSSを書いている場合にはまったく考える必要のないエッジ・ケースで時間を浪費したので、ストレスが溜まった。既にいくつか見つけてしまったマイナーな解決できそうもない問題やMedia Queries Level 4の範囲指定クエリーのこととかで更に気が重い。それらが表面化する頃には、多数のファイルでメディア・クエリーを分散させつつ投げつけても怒られないHTTPS + HTTP/2時代になっていることに期待したい。
このウェブサイトでも同梱しているGruntプラグインのテストがてら稼働させ始めた。メディア・クエリーを抜き出すと以下のような順序で最後に追加されている。
@media (min-width: 352px) {}
@media (min-width: 39.118rem) {}
@media (min-width: 53.487rem) {}
@media not screen {}
@media print {}
ちゃんと動いていそうだ。