Node-Sass Logo technology http://www.ligu.net/technology-brand/nodesass-logo-154345
seen from South Korea
seen from Singapore
seen from Norway
seen from South Korea
seen from China
seen from China

seen from Germany
seen from China

seen from Australia

seen from United States
seen from China

seen from Malaysia
seen from United States
seen from United States

seen from Vietnam

seen from Serbia

seen from Libya
seen from Japan
seen from United States
seen from Bulgaria
Node-Sass Logo technology http://www.ligu.net/technology-brand/nodesass-logo-154345
脱Compassしたいけど@importでCSSスプライトを作る機能は捨てがたかったので作った話
この記事はCSS Advent Calendar 2016の23日目の記事です。
こんにちは、技術推進室の色川です。
今年も残すところわずかとなりましたがいかがお過ごしでしょうか。 私はというとこの一年取り組んできた社内のフロントエンド開発環境整備の締めくくりとして、とあるサービスで未だ使われていた Compass からの脱却に勤しんでおりました。
Compass といえばかつては「CSS を書くなら Compass を使え」とまで言う人もいたほどですが、その機能の多くは PostCSS に取って代わられ、ここ数年は話を聞くこともなくなりました。GitHub にも「Compass is no longer actively maintained.」とか「Depreciated: Compass is no longer supported.」などと書かれており、もう完全に過去のものとなってしまったようです。
そんな状況の Compass ですが、脱却を考えたのは別の2つの理由にあります。 1つは速度です。Compass を使う以上 Ruby 版の Sass を使わざるを得ないところ、Ruby 版は node-sass(C/C++ で書かれた LibSass の Node.js バインディング) と比べ格段に遅いのです。 もう1つは環境整備の煩雑さです。Ruby を使うのでその環境構築手順等を保守しなければならず、やれ動かないとか Windows だとどうすればといったトラブルシュートもその分増えます。Node.js で完結できるならそれに越したことはありません。
そんなわけで Compass から、というより Ruby から脱却したいと考えたわけです。
Compass とは何だったのか
Compass を知らずして脱却もないわけですが、導入した前任者は既に退職し、私自身は未経験。一番の課題は「Compass よう分からん」ということで、2016年も終わろうかというのに Compass 入門したりしてました。
それで分かったのは、大雑把に言えば「Compass = Mixin と Function のライブラリ集 + CSS スプライト生成機能」だということです。他にも、コンパイルやいわゆる scaffold を行うコマンドなども含まれていましたが、利用していたのは主にその2機能でした。
移行方法を模索する
目的が「脱 Ruby」になっていたので、まずは Node.js 版の Compass がないか探しました。 すぐに compass-node というライブラリが見つかりましたが、こちらも随分メンテナンスされていないせいか弊社の環境では動きませんでした。
気を取り直して探していると、今度は compass-importer というライブラリを見つけました。 これは Sass の @import の処理をフックする importer として動作するもので、@import "compass"; という記述があると Compass のファイルを読み込んでくれます。 Mixin と Function についてはどれが Compass のものか名前だけで判断するのが難しく、利用箇所を漏れなく洗い出すのが困難に思われたので、これを使うことにしました。
残すは CSS スプライト生成機能ですが、spritesmith を使った gulp タスクを書いて Compass とオサラバした、みたいなエントリは見つかっても、Compass のように @import "my-icons/*.png"; などと書いておけば自動的に処理してくれるものはありません。
見つかったエントリと同じようにそこだけ別の方法で処理することも考えたのですが、どう見ても Compass の方が簡単で汎用的です。Mixin などについてはだいぶラクできたので、ここはひとつ作ってみることにしました。
Compass 互換の CSS スプライト生成ライブラリ
compass-importer のおかげで @import をフックできることが分かったので、いくつかの importer ライブラリのコードを読みつつ、CSS スプライトを生成するライブラリを書きました。 sprite-magic-importer
特徴
Sass コード内に @import "my-icons/*.png"; のように書くだけでスプライト画像が生成され、それを利用するためのコードが埋め込まれます。
all-#{$map}-sprites や #{$map}-sprite() など、一部の mixin も定義します。
Magic Selectors にも対応しています。
一部の設定変数 はそのまま利用できます。
本家にはない機能として Retina 対応もしています。
本家との違い
スプライト画像の生成に関する設定は、Sass の変数ではなくライブラリのオプションで指定する必要があります。
内部では spritesmith を利用しているため、レイアウトの指定方法など、細かいところでの互換性はありません。
画像のハッシュ値はファイル名には入らず、background-image の URL パラメータとして付与されます。(スプライト画像ファイル名は固定です。)
sprite-map() を使ったスプライト生成や、それと合わせて利用する関数群は利用できません。(これを実現するには functions を使う必要があるようです。)
Node.js で Compass を処理する
node-sass の importer オプションは、配列にすることで複数の importer を使うように指示できます。これを利用して compass-importer と sprite-magic-importer を指定すれば、コードを大幅に修正することなく Compass を処理できるはずです。
ところが、上記の順で指定したところ、スプライト生成の指定のところでエラーになってしまいました。
Error in plugin 'sass' Message: src/sass/app/_sprite.scss Error: File to import not found or unreadable: app/*.png Parent style sheet: /Users/...snip.../frontend/src/sass/app/_sprite.scss on line 5 of src/sass/app/_sprite.scss >> @import "app/*.png"; ^
調べたところ、importer は自分が処理しないパラメータをスルーすべきところ、compass-importer は "compass" 以外の指定でもパスを解決していたため、後続の importer に処理が回っていませんでした。 仕方がないので以下のように順番を変えてやると、今度こそ Mixin も CSS スプライトも正しく処理することができました。
var sass = require('gulp-sass'); var SpriteMagicImporter = require('sprite-magic-importer'); var CompassImporter = require('compass-importer') gulp.task('build:compass', function() { return gulp.src('src/sass/**/*.scss') .pipe(sass({ importer: [ SpriteMagicImporter({ ... }), CompassImporter ], outputStyle: 'expanded' })) .on('error', sass.logError)) .pipe(gulp.dest('path/to/dist')); });
まとめ
Ruby/Compass を使っている場合は、今回紹介した方法ですんなり node-sass に移行できるかもしれません。
sprite-magic-importer 単体で使っても便利なので(Compass のスプライト機能が便利なわけですが)、よかったら試してみてください。
※HTTP/2 の世界では CSS スプライトは不要らしいんですけどね...
PostCSSでCSSを変換する
1年ほど前に作った開発環境のテンプレートのようなものを最近使う機会があったのだけど、いざ使ってみようとモジュールをインストールしたらgulp-sassが動作しなかった。
どうもバージョンが古いせいだったようなのだけど、自分も他の人もSCSSのすべての機能を使いこなしているわけではない(というか、ほとんどネストくらいしか使っていない)ので、node-sassと違ってバイナリをコンパイルする必要がないPostCSSを使ったほうが良いのではないかと思って使ってみることにした。
最初に必要なモジュールをインストールする。
$ npm install postcss postcss-cli postcss-import postcss-nested autoprefixer
とりあえずimportとnestedとautoprefixerをインストールした。
postcss.jsonというファイル名で設定ファイルを書く。
{ "use": [ "postcss-import", "postcss-nested", "autoprefixer" ], "input": "index.css", "output": "output.css", "local-plugins": true, "autoprefixer": { "browsers": "last 2 version" } }
useには使用するモジュールを書く必要があるのだけど、importを使用する場合は先頭に書く必要がある。あとはCSSをいくつか書く。
clearfix.cssというファイル名でCSSを書く。
.clearfix::after { content: ""; clear: both; display: block; }
index.cssというファイル名でCSSを書く。
@import "./clearfix.css"; /* comment */ div { opacity: 0.5; border-radius: 5px; animation: anime 1s linear 0s; &.div { opacity: 1; } } @keyframes anime { from { transform: translateY(0px); } to { transform: translateY(100px); } }
これらをpostcss-cliから変換する。
$ ./node_modules/.bin/postcss --config postcss.json
変換されたoutput.cssは以下の通り。
.clearfix::after { content: ""; clear: both; display: block; } /* comment */ div { opacity: 0.5; border-radius: 5px; -webkit-animation: anime 1s linear 0s; animation: anime 1s linear 0s; } div.div { opacity: 1; } @-webkit-keyframes anime { from { -webkit-transform: translateY(0px); transform: translateY(0px); } to { -webkit-transform: translateY(100px); transform: translateY(100px); } } @keyframes anime { from { -webkit-transform: translateY(0px); transform: translateY(0px); } to { -webkit-transform: translateY(100px); transform: translateY(100px); } }
今回はファイル名を指定したけれど、ディレクトリを指定することもできるようなので用途に応じて使用方法を変えれば良いと思う。
変換も早いし、よほどnode.jsが古くなければ動作すると思うのでnode-sassを使う必要がなくなるかな、と思った。
Using node-sass with latest version of io.js
When using node-sass together with io.js, one of the problems is that it’s not updated to work with the latest version of io.js (at the time of writing, v.1.6.2). Currently node-sass only supports io.js until v.1.2.
This causes the installation of node-sass and any libraries that depends on node-sass to fail to fetch all resources during installation, which eventually causes processes that tries…
View On WordPress