All Articles

PHPで動くCSSプリプロセッサ作ってみたよ

あけましておめでとうございます、ということで新年最初のエントリです。

年末年始の習作をなにか

去年後半は外出することが増えて、ガッツリプログラムを書く機会が少しづつ減ってきてまして(不満ではなく)、年末年始の長期休暇を利用して何か1つ作ってみたいなーって思ってました(他にもほっぽりのプロダクトとかあるんですが><)。

お題を何か

せっかく作るんだし、あんまり自分が手を付けていなかった分野、もしくは言語でやりたいなーと思ってたんですが、とあるきっかけからテーマは何となく決まりました。

  1. あ、そういえば来年(この時、2012年)CSS Nite LP26あるよね
  2. @ahomu氏が発表するし参加してるんだった
  3. altCSS系、Sass、LESS、Stylus...
  4. ( ⁰⊖⁰)…
  5. あ、おんなじの作ってみようか

こんな感じです。altCSSってデファクトが決まってない感じ(?)だし、丁度テキストデータの解析とか正規表現がへたっぴだったので、自分で使うかどうかわからんけどちょうどいいかなーというわけで。言語はとりあえずなPHPを選択。

というわけで、CSS-Preprocessor

できたものはすでにGithubにあげてます(仕事始めまでもう少しいじる予定)。使い方とかはREADMEにまとめてますので、ここでは書きません。

https://github.com/ysugimoto/pss

ちなみに、あくまで習作の成果物という位置づけで、わりとネタ感が強い一品です。すでにPHPのプリプロセッサはいくつかあるようですね。

どちらも覗いてたのですが、プログラマブルすぎててちょっと首を捻ってしまいました。

コンセプトとか

上記に反発するわけではないですが、これらはあくまで「拡張メタ言語」だと思ってます。ベースはCSSであり、ぱっと見てCSSの体裁を保っていないといけない、また「拡張部分」である部分が一見して分かるべきじゃないかなーというのがコンセプトです。例えば、ファイル中に普通に計算式が書いてあると、CSS自体が計算式をサポートしてるように見えたりしちゃいました。つまり、「どこが拡張メタ言語による記述なのか」、「どこがCSS本来の記述なのか」が完全に見た目で分離されててほしいなーと思ったわけです。

「拡張部分 = @」

というわけで、CSSにおける@ルールを拡張することにし、またCSSでは使われない文字も拡張部分として識別するようにしています。例えば、@mediaはCSS組み込みですが、それ以外のルールを拡張している感じです。そして、変数は$を識別子にしています(Selectors Level4では$を使うセレクタがあった気がしますが置いといて)。

あとは、とりあえず構文とかはSassに似せとけばとっつきやすいかなー、と。

正規表現でなんとかなると思っていた時期が僕にもありました

さて、本題です。習作なので、機能よりも自分がどれだけ苦労したか、解決したかが重要ですね。 さて、作り始めるに当たって、

あーCSSのフォーマットに従って正規表現で置換してけばいけるかなー

なんて思ってましたが、全然ダメでした。もともとそれほど正規表現が得意ではないうえに、複雑な構文が出てくるとお手上げでした…。上手な人ならパパっとやっちゃうんでしょうね。ですが、これがターニングポイントでした。

そうだ、構文解析ちゃんとやろう

正規表現だと構文に問題がある所が検出しづらいですし、

というわけで、ザルじゃないようにしたいなーと思い、構文解析をちゃんとするようにロジックを考え直しました。 おかげで少しテキスト解析のスキルが上がったと思います。あ、もちろん内部では正規表現ガリガリしてます。僕のようなレベルでも解析できる部分まで単語を細分化してるので、なんとか行けました(冗長な部分は多分にありますが)。

その結果、単純な構文だけでなく、セクショニングや制御文の実装までに至りました。特に四則演算のあたりは書いてて楽しかったです。スクリプトのインタプリタの気持ちに少しだけ近づけました(´∀`)

あらゆる構文を外部プラグインへ

これはPSSの特徴でもあるのですが、拡張構文とパーサは分離されています。つまり、Sassなどにあるmixinやextendといった構文は組み込みではなく、外部プラグインという形で実装されています(多分Sassも内部ではそうなんでしょうが)。なので、拡張構文は好きなようにカスタマイズできますし、新規追加も比較的ラクです。また、forやifなども外部コントロールになっているので、同じく好きな構文を作ることができます。

CSSに易しく、それでいてプログラマブル

処理の流れは、「元ファイルを解析」→「Selectorクラスインスタンスにマッピング」→「インスタンスリストからレンダリング」→「コンパイル完了」という感じです。元ファイルを一度全てPHPのクラスインスタンスにマッピングするので、逆に完全にプログラムからCSSを吐き出すことも可能です(できるよ、というレベルで実際にやるかどうかは別として)。クラスの継承関係も今回は割と上手く作れたと思っていますね。とはいえ、元ファイルはほぼCSSなので、意識することは無いと思います(拡張構文を使いすぎなければ)

まとめと感想とか

というわけで、年末年始の3日くらいでざざーっと書いたものでした。CSS程度の簡単な構文解析とか、正規表現のレベルがちょっと上った感じがしますね。内部のコードはブラシュアップが必要ですが…。

おかげで年末年始は退屈しませんでした(;´Д`)

まだまだアラが多いので、もしも興味を持って頂けた方は、使ってみた感想とかフィードバックを頂けると嬉しいです。 使い方はGithubを参照して下さいませー。

https://github.com/ysugimoto/pss

それでは、今年もよろしくお願い致します!