CS-Cartのドキュメントとかマニュアルが少なくてなかなかに苦労しているので、後発さんにちょっとは役に立つ記事にしようと思っているんですがよくある技術ブログみたいに上手くかけないのでご容赦ください。
今回はCSSファイルとLESSファイルの読み込みの順番についてです。アドオンで読み込ませたCSSファイルとLESSファイル、上手くextend出来なくて何時間かドハマリしました。
CS-Cartでは、スタイルシートはLESSを使って書かれています。しかも、CS-Cartでは事前にコンパイルする必要がなく、指定したLESSファイルをlessphpでコンパイルしてCSS化したものをキャッシュ化してくれます。
楽じゃん。って思ってたら、このlessphpを噛ませる部分が曲者でした。
スタイルの読み込み順
公式のドキュメントを見ると、読み込みの順番はこんな感じです。
- design/themes/basic/templates/common/styles.tpl
- <style></style>タグでdesign/themes/basic/templates/common/styles.tplテンプレートに追加されたすべてのインラインスタイル
- プリセットされたlessファイル
- ビジュアル・エディタのカスタムCSSフィールドに追加されたもの
- アドオンのスタイル(プライオリティによって定義された順序)
参考 http://docs.cs-cart.jp/docs/css
何の文句もない読み込み順です。
ところがCSSとLESSの違いでハマった
LESS推奨でもCSSファイルを使いたい時だってあります。1箇所や2箇所程度extendするだけだったり、LESS使うまでもない記述だったり。今回のアドオンはCSSもLESSも用意しておいてあげたいアドオンだったので、それぞれをスタイルシートのロードにフックして読み込ませることに。
ちなみにですけど、この記事を見ている人が分からないわけはないと思いつつ一応書いておきます。
styles.post.tplにフック
/design/themes/利用中テーマ/templates/addons/アドオン名/hooks/index/styles.post.tpl
{style src="addons/my_addon_demo/style.less"} {style src="addons/my_addon_demo/style.css"}
このstyleブロックは、SmartyのCS-Cart独自ブロック関数で、meta用のタグを吐き出してくれます。
CSSとLESSファイルを追加
/design/themes/利用中テーマ/css/addons/アドオン名/style.css
.demo { background-color:#0000; }
/design/themes/利用中テーマ/css/addons/アドオン名/style.less
@color: #666666; .demo{ &.demo-box{ color:darken(@color,20%); background-color:darken(@color,5%); } .subdemo2{ background-color:@color; } }
こんな感じにしました。
これを反映して、管理メニューからキャッシュをクリア・・・。が、フロントをリロードしても反映されてない。
原因を探す
生成された後のstandalone.cssを見てみると、ヘッダー部分にコメントアウトしてロードしたCSSファイルとLESSファイルのパスが書かれています。フックの時のファイルパスを間違えたかなと確認しましたが、そうでもないです。
前回あった、キャッシュが消えきれてないパターンかな?と、生成された後のCSSファイルを手動でキャッシュ削除。(生成されたCSSの場所は、headタグ内を見ればURLから場所が分かるので割愛します。)反映されません。
いや、全く反映されないわけじゃないんです。
一部・・・反映され・・・あれ?!
standalone.cssがながーーーいので、ぱっと見だけしかしてなくて気づいてなかったんですが、CSSファイルに記述したものが一番上にいる?これなんだろう。プライオリティ勘違いしたっけな?そんなこともないし・・・。そうだ!!このCSS作ってるところ読もっと!
結局こうなります。
cssを作ってる部分を読む
先にも書いた通りlessphpでLESSをコンパイルしているわけですが、具体的な流れとしてはこんな感じです。
- スタイルの読み込み順で書いた通りの順番でCSSメタリンクを拾いあげる。
- リンク先のファイルがCSS拡張子ならCSS用の1個の文字列変数にまとめあげる。
- リンク先のファイルがCSS拡張子以外ならこれもまたLESS用の1個の文字列変数にまとめあげる。
- LESS用の文字列変数をlessphp関数に投げる。
- 返ってきたコンパイルされたCSSを、CSS用の文字列変数と連結してCSSファイルとしてキャッシュを生成する。
え!?
この「え!?」の場所は /app/functions/fn.common.phpのfn_merge_styles()です。
$compiled_content = $compiled_css . "\n" . $compiled_less; /* 色々処理が挟まって・・・*/ Storage::instance('statics')->put($relative_path . '/' . $filename . $gz_suffix, array( 'contents' => $header . $compiled_content, 'compress' => Registry::get('config.tweaks.gzip_css_js'), 'caching' => true ));
- $compiled_css
CSS拡張子のファイルから読み込んだ文字列が連結が格納。 - $compiled_less
「CSS拡張子以外」のフィアルから読み込んだ文字列をlessphpに投げてコンパイルしれた文字列を格納
・・・お分かりいただけただろうか。
諸々の変数の中身なんかは割愛しますが、つまり、「CSSファイルをロード後にLESSから作ったCSSを足す。追記的な意味で。」ってことです。公式にある読み込み順はあくまでも、「CSS」と「LESS」のそれぞれの読み込み順であって、CSSとLESSを合わせた最終的なCSSは「CSSの後にLESSから生成されたCSS」が来ることになります。
プライオリティ100のaddonのCSSとLESS、プライオリティ999のaddonのCSSがあった場合
- プライオリティ100のaddonのCSS
- プライオリティ999のaddonのCSS
- プライオリティ100のLESSからコンパイルされたCSS
という順番で最終的なCSSが仕上がってくるということです。
なるほどなるほどなるほどなるほどなるほどなるほど・・・。
でもそりゃそうですよね。LESSからコンパイルされたCSSにはもうプライオリティによる境目なんていうものは存在していなくて、全LESSファイルを統合してコンパイルした結果でしかないので、「ここからここまでがプライオリティ100のCSS」みたいなのは無いわけですよね。
CS-Cartの場合は「CSSファイルの中身」「LESSからコンパイルされたCSS」という順番で最終的なCSSファイルが生成されるので、CSSとLESSを混在させる時は気をつけないと、妙に反映されたり反映されなかったりする場所が出てきてしまいます。
例えば、アドオンでテーマのカスタマイズをする時にCSSファイルで対応しようとした場合、そのCSSファイルの中身は結局テーマやその他アドオンたちのLESSコンパイル結果に上書きされることになるので「!important」とかをいちいちつけないと読み込まれることがありません。
どっちを先に読むのが正解か
fn.common.phpのfn_merge_styles()にはフックポイントもないので、本体に手をいれるしかないのです。
CSSとLESSコンパイル結果のどっちを優先すべき、どっちを後に読まれるようにするかというのは、個々のスタンスの差とかで正解は無い気はしていて、仕様としては何も問題もないと思ってはいます。
が、あくまで個人的には、両方を読み込むこと前提なのであれば、LESSは全体的なコードを書いて、CSSは最後にちょい足ししたり、LESSが分からない人がデザインに手を入れる時に使うのではないかなぁと思います。要はLESSは誕生日ケーキ本体で、CSSはロウソク。みたいな。これを考えると、私としてはCSSファイルをLESSコンパイルの後に吐き出すようにしてくれたほうがいいのになぁと思います。
っていうお話でした。