CSS整形
CSS整形ツールは、ブラウザ内でスタイルシートのインデントを整え、最小化します。解析ではなくトークン化で動くため、未知の@ルールも、このツールより新しい構文も、そのまま通ります。パーサーは認識できないものを拒否します。フォーマッターにとって、理解できないものを消すより保存する方が常に正しいからです。
CSS整形はどう動きますか?
CSSの整形は、その大半が「対象がどこで始まりどこで終わるか」を知ることに尽きます。そして、素朴なやり方では間違う場所が4つあります。
波括弧は必ずしもブロックではない
content: "}"は文字列の中に閉じ波括弧を含み、/* } */はコメントの中に含みます。こうした状態を追跡せずに波括弧で分割すると、疑似要素のカウンターを含むスタイルシートも、コメントアウトされたルールを含むスタイルシートも、台無しにするフォーマッターができあがります。上のサンプルには、その両方が意図的に入っています。
コロンは必ずしもプロパティの区切りではない
background: url(https://example.com/x.png)は、値の中にコロンを含みます。カスタムプロパティの値には何でも入ります。それこそがカスタムプロパティの有用性です。分割は、括弧の中にない最初のコロンで行われます。
カンマは必ずしもセレクターの区切りではない
:is(a, b) spanはカンマを含む1つのセレクターであり、:nth-child(2n of .x, .y)も同じです。セレクターリストを裸のカンマで分割すると、どちらも壊れます。分割はトップレベルでのみ行われます。これにより、値の中のrgb(0, 0, 0)も無傷で保たれます。
トークナイザーはパーサーより長持ちする
CSSは絶えず構文を増やしています。ネスト、@container、@layer、:has()、相対色構文などです。パーサーはそれぞれをモデル化しなければならず、知らないものは拒否します。つまり、ブラウザがすでに受け付けているCSSで壊れるのです。トークナイザーが知るべきことは、文字列、コメント、ブロック、セミコロンがどこにあるかだけで、それはCSS 1以来変わっていません。未知の構文は捨てられるのではなくそのまま通ります。フォーマッターが責任を持って取れる挙動は、それだけです。
最小化でもライセンスコメントは残る
/*! … */は、ミニファイアーが保持すべきコメントの目印という慣習です。通常そこにはライセンスが書かれており、これを剥がすと、スタイルシートの配布条件に実際に違反しかねません。それ以外はすべて削除します。閉じ波括弧の直前のセミコロンも削除します。宣言と、その後に続く「何もないもの」を区切っているだけだからです。
ここの最小化がしないのは、値の書き換えです。#ffffffを#fffへ短縮しない、ルールをマージしない、順序も変えない。どれも確かな削減効果であると同時に、ミニファイアーがバグの表面を持つコンパイラーと化す場所でもあります。ビルドパイプラインには本物のミニファイアーを使ってください。このツールは、スタイルシートを貼り付けられる大きさにするためのものです。
入力
a,b{color:red;margin:0}整形結果
a,
b {
color: red;
margin: 0;
}CSS整形が対応するオプションとエッジケースは?
| パラメータ | 型 | デフォルト | 動作とエッジケース |
|---|---|---|---|
| インデント | スペース | 2 | ネストレベルごとに適用され、メディアクエリ内のルールは2インデントされます。 |
| 1行に1セレクタ | 真偽値 | on | カンマ区切りのリスト内の各セレクタを別々の行に配置します。トップレベルでのみ分割されるため、:is(a, b)はそのまま維持されます。 |
| ルール間の空行 | 真偽値 | on | 各トップレベルルールの後に空行を入れることで、長いスタイルシートをスキャンしやすくします。 |
| コメント保持 | 真偽値 | on | 複数行コメントは、ASCIIアートのセクションヘッダーが一般的で、再整形すると破壊されるため、内部の形状を維持します。 |
| 文字列 | 保持 | — | content: "}" には閉じ中括弧が含まれます。文字列の状態を追跡することで、そのブロックの終了を防ぎます。 |
| url() | 全体を一括処理 | — | 引用符のない url() には、データURIのコロンや括弧など、構造上の文字が含まれることがあります。 |
| アットルール | ネスト | — | @media, @supports, @layer, @container およびそれ以降のものです。未知のatルールは破棄されずにそのまま通過します。 |
| ミニファイ | 空白のみ | — | 空白を圧縮し、ブロック内の最後のセミコロンを削除します。値の書き換えやルールの結合は行いません——それはビルドステップの仕事であり、ペーストボックスの仕事ではありません。 |
| ライセンスコメント | /*! … */ | 保持 | すべてのミニファイアが従う規約に従い、ミニファイ時にも保持されます。削除すると、ライセンスに違反する可能性があります。 |
よくある質問
ネストしたCSSや@containerクエリを壊しませんか?
壊しません。それこそが、解析ではなくトークン化する意味です。フォーマッターが知るべきことは、文字列、コメント、ブロックがどこで始まりどこで終わるかだけです。@ルールの意味を理解する必要はありません。このツールより新しい構文もそのまま通ります。パーサーが未知のものに出会ったときと、正反対の挙動です。
最小化した出力にコメントが残っているのはなぜですか?
そのコメントが/*!で始まっているからです。/*ではなく。これは、残すべきコメントに対してすべてのミニファイアーが従う慣習であり、たいていライセンスが書かれています。剥がすと、スタイルシートの配布条件に違反しかねません。通常のブロックコメントは削除されます。
本物のビルドツールより、最小化で減るサイズが小さいのはなぜですか?
ここでは空白を取り除くだけだからです。本番用のミニファイアーは、さらに色を短縮し、重複するルールをマージし、上書きされた宣言を落とし、ショートハンドを書き換えます。どれも確かな削減効果であると同時に、エッジケースを誤れば挙動を変えかねない変換でもあります。ビルドパイプラインには本物のミニファイアーを。このツールは、スタイルシートをどこかに貼り付けられる大きさにするためのものです。
セレクターリストがカンマごとに分割されなかったのはなぜですか?
カンマの一部が関数型疑似クラスの中にあるからです。:is(.card, .panel)は、たまたまカンマを含む1つのセレクターであり、そこで分割すると、どちらも不正な2つのセレクターができあがります。分割はトップレベルでのみ行われます。値の中のrgb(0, 0, 0)を無傷で保つのと同じルールです。
CSSの検証もしてくれますか?
しません。プロパティのスペルミスや不正な値を含むスタイルシートも、警告なしに整形します。未知のプロパティを拒否するフォーマッターは、すべてのベンダープレフィックスとすべての新機能を拒否することになるからです。検証が必要なら、ブラウザ自身のDevToolsがStylesパネルで未知のプロパティに印を付けてくれます。どの静的なリストよりも信頼できるシグナルです。
スタイルシートはアップロードされますか?
いいえ。トークン化と整形はブラウザ内で動作します。CSSはペイロードほどの重要度ではありませんが、それでも意味はあります。未公開製品のスタイルシートはその製品について記述し、内部ツールのスタイルシートはその内部ツールについて記述しているのです。