$shibayu36->blog;

クラスター株式会社のソフトウェアエンジニアです。エンジニアリングや読書などについて書いています。

gulp-autoprefixerを使ってCSSのベンダープレフィックス付与を自動化する

 今回はgulp-autoprefixerを使ってCSSのベンダープレフィックス付与を自動化する話です。サンプルは https://github.com/shibayu36/javascript-playground/tree/master/try-autoprefixer においてあります。

解決したい課題

  • サポート状況を見ながらちまちまCSSのベンダープレフィックスを付けるのは面倒
  • 面倒なだけならいいが、つけ忘れによるバグも発生する可能性がある

 こういう課題は自動化で解決したい。

解決策

gulp-autoprefixerによる自動化

 以下の手順で導入できる。

  • 必要なモジュールのインストール
  • gulpのtaskを書く
  • CSSを書いてコンパイルする

必要なモジュールのインストール

$ npm install -D gulp
$ npm install -D gulp-autoprefixer

gulpのtaskを書く

 今回はsrc/css/以下のCSSファイルに自動でベンダープレフィックスを付けて、static/css/以下に配置するというタスクを書いてみる。

var gulp = require('gulp');
var autoprefixer = require('gulp-autoprefixer');

gulp.task('compile-css', function () {
    return gulp.src(['src/css/*.css'])
        .pipe(autoprefixer({
            browsers: ['last 2 version', 'iOS >= 8.1', 'Android >= 4.4'],
            cascade: false
        }))
        .pipe(gulp.dest('static/css'));
});

 やっていることは以下のとおり。

  • gulp.srcで元となるファイルをsrc/css/*.cssに指定
  • gulp-autoprefixerに通し、自動でベンダープレフィックスを付ける
    • browsersのオプションで自分のサポートしたいブラウザを指定。今回はメインブラウザの最新2バージョン、iOS 8.1以上、Android Browser 4.4以上という指定を行った
    • cascade falseにして、変に整形されないようにしておく
  • gulp.destを使って結果をstatic/css/以下に出力

 browsersの指定方法だけ少し複雑で、いろんな指定方法が出来る。メインブラウザnバージョンとか、利用割合n%以上のブラウザとか、バージョンn以上のFirefoxとかの指定が可能。他にも自分のGoogle Analyticsをエクスポートして、自分のサービスの利用しているもので1%以上を占めるブラウザを全て対象にするなどといったことも出来る。詳しくは以下のドキュメントを参照。

CSSを書いてコンパイルする

 実際にCSSを書いてコンパイルしてみる。

src/css/app.css

:fullscreen a {
    display: flex
}

 以下のコマンドを実行する。

$(npm bin)/gulp compile-css

 static/css/app.cssに以下のようなCSSが生成された。あとはこ本番ではこれを配信すれば良いだけになった。

:-webkit-full-screen a {
    display: -webkit-flex;
    display: flex
}
:-moz-full-screen a {
    display: flex
}
:-ms-fullscreen a {
    display: -ms-flexbox;
    display: flex
}
:fullscreen a {
    display: -webkit-flex;
    display: -ms-flexbox;
    display: flex
}

lessなどと併用する

 lessなどを利用していても簡単に導入できる。今回のautoprefixerはPostCSS という仕組みに乗っかっていて、単にCSSを入力として何らかのCSSの出力を返す形式になっているだけなので、lessコンパイル後のCSSに対して適用すれば良い。

 gulp-lessをインストールする。

npm install -D gulp-less

 タスクはこういう感じ。

var gulp = require('gulp');
var autoprefixer = require('gulp-autoprefixer');
var less = require('gulp-less');

gulp.task('compile-css-with-less', function () {
    return gulp.src(['src/less/*.less'])
        .pipe(less())
        .pipe(autoprefixer({
            browsers: ['last 2 version', 'iOS >= 8.1', 'Android >= 4.4'],
            cascade: false
        }))
        .pipe(gulp.dest('static/css'));
});

 以下のようにlessを書く。
src/less/app.less

:fullscreen {
    a {
        display: flex
    }
}

 コンパイルする。

$(npm bin)/gulp compile-css-with-less

 static/css/app.cssに結果が出力される。

まとめ

 gulp-autoprefixerを使ってベンダープレフィックス付与の自動化を行ってみた。こういうのをほうっておくとデザイナ負担がどんどん上がっていくので、どんどん自動化していきたい。

CSSのブラウザサポート状況を自動でチェックできるdoiuseが便利

 最近書いているCSSがそもそも今サービスが推奨しているブラウザでサポートされているのかチェックするのだるいと思っていたら、doiuseという便利なツールを見つけた。

doiuseとは

https://www.npmjs.com/package/doiuse

 CSSのブラウザサポートのチェックをしてくれるモジュール。caniuse のデータベースを利用して、ブラウザと自分が書いているCSSを指定して、サポートされていないCSSの書き方を見つけてくれる。

試す環境を用意する

 とりあえず試すための環境を用意する。適当なディレクトリを作って、必要なライブラリをインストールする。また、検証するためにbootstrapも入れておく。

$ mkdir try-doiuse
$ cd try-doiuse
$ npm install --save-dev doiuse
$ npm install --save-dev bootstrap

 もしくは自分が試した環境もあるので、https://github.com/shibayu36/javascript-playground をcloneして

$ cd try-doiuse
$ npm install

でも試す環境はセットアップできる。

doiuseで書いたCSSをチェックしてみる

 bootstrapの提供しているCSSについてブラウザサポートをチェックしてみる。基本的には

doiuse --browsers '...' [FILE]

というCLIでチェックできる。browsersの部分にはbrowserslist に書いてあるような記法を用いることができる。

メインブラウザの直近2バージョンのサポート状況をチェックする

 まず、bootstrap.cssのメインブラウザの直近の2バージョンのサポート状況をチェックしてみる。

$(npm bin)/doiuse --browsers 'last 2 version' node_modules/bootstrap/dist/css/bootstrap.css

 すると以下のようにずらりとサポートされていないものや、一部サポートのもののリストが表示される。

node_modules/bootstrap/dist/css/bootstrap.css:9:1: CSS text-size-adjust not supported by: IE (10,11), Edge (12,13), Firefox (46,47), Chrome (50,51), Safari (9,9.1), Opera (37,38) (text-size-adjust)
node_modules/bootstrap/dist/css/bootstrap.css:10:1: CSS text-size-adjust not supported by: IE (10,11), Edge (12,13), Firefox (46,47), Chrome (50,51), Safari (9,9.1), Opera (37,38) (text-size-adjust)
node_modules/bootstrap/dist/css/bootstrap.css:131:1: CSS Appearance not supported by: IE (10,11), IE Mobile (10) and only partially supported by: Edge (12,13), Firefox (46,47), Chrome (50,51), Safari (9,9.1), Opera (37,38), iOS Safari (9.0-9.2,9.3), IE Mobile (11) (css-appearance)
...

 これだと流石に見にくいので、どういうエラーがあるのか知るために、適当に整形してみる。あんまりパースしやすい形式ではないけど、cutやsortやuniqを使って強引に整形してみる。最初の数字がそのエラーが出た回数で、それ以降がエラーの内容になっている。

$ $(npm bin)/doiuse --browsers 'last 2 version' node_modules/bootstrap/dist/css/bootstrap.css | cut -d':' -f 4- | sort | uniq -c | sort -rn
  12  CSS Filter Effects not supported by: IE (10,11), Edge (12), IE Mobile (10,11) and only partially supported by: Edge (13) (css-filters)
  10  CSS3 Cursors (original values) not supported by: iOS Safari (9.0-9.2,9.3), IE Mobile (10,11) and only partially supported by: Edge (12,13) (css3-cursors)
   5  CSS Appearance not supported by: IE (10,11), IE Mobile (10) and only partially supported by: Edge (12,13), Firefox (46,47), Chrome (50,51), Safari (9,9.1), Opera (37,38), iOS Safari (9.0-9.2,9.3), IE Mobile (11) (css-appearance)
   4  CSS3 3D Transforms only partially supported by: IE (10,11), IE Mobile (10,11) (transforms3d)
   ...

 これを見ると、基本的には直近のブラウザには対応しているけど、一部分だけブラウザサポートしていないCSSが混ざっていることが分かった。CSS Filter EffectsというのはIE 10や11ではサポートしていないみたい。caniuse を見てもそうだった。

 しかし、このCSSの中にはモバイルブラウザ用のものも混ざっていたりしてそれが誤検出されている場合もあるし、もしかしたらJSを使うと出来るのかもしれないので、Bootstrapのsupport で見て取れるように、基本的には対応していることが分かる。

IE8も含めてサポート状況をチェックする

 さらにBootstrapはIE8には対応していないと書かれているので、IE8以上も含めて調べてみる。

$(npm bin)/doiuse --browsers 'last 2 version, IE >= 8' node_modules/bootstrap/dist/css/bootstrap.css | cut -d':' -f 4- | sort | uniq -c | sort -rn
 281  CSS Generated content for pseudo-elements only partially supported by: IE (8) (css-gencontent)
 129  CSS3 Border-radius (rounded corners) not supported by: IE (8) (border-radius)
  78  CSS3 Colors not supported by: IE (8) (css3-colors)
  68  CSS3 Media Queries not supported by: IE (8) (css-mediaqueries)
  58  CSS3 Box-shadow not supported by: IE (8) (css-boxshadow)
  45  CSS3 selectors only partially supported by: IE (8) (css-sel3)
  ...

 BootStrapはIE8以下のブラウザサポートは切っているということなので、IE8以上でサポート情報を調べると、IE8では使えないものをどんどん使っていることが検出できた。

その他の指定方法

 他にもいろんなブラウザ指定方法ができて、例えばメインブラウザの最新2つ、iOS 8.1以上、Android 4.1以上で検出したい場合は以下のように指定すれば良い。

$(npm bin)/doiuse --browsers 'last 2 version, iOS >= 8.1, Android >= 4.1' node_modules/bootstrap/dist/css/bootstrap.css

まとめ

 このようにdoiuseを使えば自分が書いたCSSのブラウザサポート状況を確認することが出来る。またdoiuseのAPIを見ていると、CLIだけではなくてJS用のAPIとかもあるので、自動でCI回すこととかも出来そう。機会があったらそのようにしてみても良いかもしれない。

 CSSについて、デザイナが気合で頑張るというのは辛い話なので、こういう自動化ツールをどんどん利用していきたい。

その他技術的話題

 最近(?)はCSSに自動でvendor prefixをつけたり、自動でLintを書けたりといろいろなことができるようになっているけど、これはPostCSSというツールが出来たからみたいだった。この仕組みを使えば新しいCSSの仕様を利用するcssnextというbabelのような仕組みを使ったり、自動でおかしいところを検出したりといろいろなことができる。

 doiuseもこの仕組みに乗っかって検出しているみたいだった。PostCSSからはCSSパーサーとASTに対するAPIが提供されているので、自分でAPIを利用して、いろんなプラグインを書くこともできるみたい。

参考

Emacsで特定のプロジェクトでだけ編集モードの設定を変える

 最近JSを触っていて、このプロジェクトはインデントが2だけど、このプロジェクトはインデントが4で、プロジェクトごとに設定できないかなーという課題意識を持っていた。今まで全く知らなかったのだけど、これは.dir-local.elというのを利用すれば出来るようだった。

 設定は単純で特定のプロジェクトのrootディレクトリに.dir-local.elというファイルを置くだけ。例えばあるプロジェクトではjs2-modeのインデントを2にしたいという時は、.dir-local.elに以下のように記述しておくだけでいい。

((js-mode (js2-basic-offset . 2)))

 こんな便利なものをいままで知らなかったので悲しい。