CSSプリプロセッサやポストプロセッサで出力されたCSSの整形

公開

SassなどのCSSプリプロセッサやAutoprefixerのようなポストプロセッサを利用すると、プロセッサ規定のインデントや改行方法でCSSが整形されます。これについては@myakuraさんがAutoprefixer ― CSSのベンダー接頭辞をいろいろする - fragmentaryの最後で懸念事項として上げられていましたし、僕も2011年の年末にSassで出力するCSSファイルを自社のCSS記述ルールに合わせるヒントで、Sassをカスタマイズして解決する方法を紹介したりもしました。

Autoprefixerのdependenceであるpostcss(Framework for CSS postproccessors)を見ると、Whitespacesという項があり、インデントやスペースを調整できることが解説されています。これを利用すれば、CSS Beautifyのようなことがオフラインで実現でき、課題が解決できるのではと思い実験してみました。

gruntgulpのプラグインを見ましたが、完全にマッチするものは見つかりませんでした。

サンプルコード

Sassでコンパイルし、Autoprefixerを通したCSS

@charset "UTF-8";

.lyt-column .unit {
  float: left;
  margin-right: 20px;
}
.lyt-column .unit.last-unit {
  margin-right: 0;
}

@media print{
  nav{
    display: none;
  }
}

pretty.js - CSSを整形するスクリプト

中程のdecl.beforerule.before等の値を変更して、整形方法を指定します。どの部分が変わるかは、コメントで記載しておきました。

var fs = require("fs")
var postcss = require("postcss");

var prettifier = postcss(function (css) {
    css.eachDecl(function (decl) {
        decl.before  = "\n";     // before property name
        decl.between = ":";      // between property name and value
    });
    css.eachRule(function (rule) {
        rule.before  = "\n\n";  // before selector
        rule.between = "";      // before {
        rule.after   = "\n";    // before }
    });
    css.eachAtRule(function (atRule) {
        atRule.before  = "\n\n";    // before @
        atRule.between = "";        // before {
        atRule.after   = "\n\n";    // before }
    });
});

var css = fs.readFileSync("before.css");
var prettycss = prettifier.process(css).css.trim();
fs.writeFile("after.css", prettycss, function () {
    console.log("Process Done!");
});

実行方法

準備

Node.jsとpostcssを利用します。npm install postcssでpostcssをプロジェクトディレクトリにインストールします。npm install -g postcssでインストールして、プロジェクトディレクトリでnpm link postcssをしても良いかもしれません。

実行

node pretty.jsを実行します。Process Done!と表示されると、after.cssが出力されています。

出力サンプル

console.logで出力してみました。

サンプル1

Sassのexpandedからスペースを取り除いたり、}の後ろに1行空行を入れたものです。
サンプル1の出力結果

サンプル2

プロパティの前のインデントを4スペースに、プロパティの後はセミコロン+スペース1つとしたものです。

css.eachDecl(function (decl) {
    decl.before  = "\n    ";     // before property name
    decl.between = ": ";         // between property name and value
});


サンプル2の出力結果

まとめ

想定通りCSSの整形が行われることが分かりました。需要があるようであれば、gruntやgulpのプラグインにしても良いのかなと考えています。Source Mapsへの対応も必要ですね。

2014.02.17追記

grunt-cssprettyをリリースしました。詳しくは、Grunt.jsでCSSの整形を行うgrunt-cssprettyを公開をご覧下さい。