クモのようにコツコツと

フロントエンドエンジニア イイダリョウの技術ブログ。略称「クモコツ」

【CSS】そうだ Autoprefixerで 自動ベンプレ付けよう(Gulpで動かす)

フロントエンド開発環境の続きです。前回はHTMLHintでHTMLの構文チェックしました。今回はAutoprefixerでCSSのベンダープレフィックスを自動で付けてみます。ベンダープレフィックスはとても悩ましい存在で、これを付けるのが面倒であるために、その機能を使うのを諦めたり、逆にこれに対応していないブラウザへへの対応を諦めたりしてきました。自動的に付けてくれるなら辛くない!それでは行きましょう!

【目次】

前回の記事
※参考:【HTML】HTMLHintで構文チェックを事始める - クモのようにコツコツと

※参考: qiita.com

ベンダープレフィックスとは何か

ベンプレ(ベンダープレフィックスの略*1)辛い。。

ベンプレとは何か。CSSのプロパティの頭に付ける接頭辞。

ベンダープレフィックス(接頭辞)とは、ブラウザベンダーが独自の拡張機能を実装したり、草案段階の仕様を先行実装する場合に、 それが拡張機能であることを明示するために付ける識別子のことです。

主要ブラウザのベンダープレフィックス

  • -moz-  …… Firefox
  • -webkit- …… Google Chrome、Safari
  • -o-    …… Opera
  • -ms-   …… Internet Explorer

※参考:ベンダープレフィックス-CSSの基本

ちなみに、Opera用の-o-については今は-webkit-でいけるようなので既に過去の書き方らしい。Chromeと同じBlinkというHTMLレンダリングを使用している。

そしてそして、Edgeも今はBlinkになったので-webkit-でいけるらしい!そのため、IEさえ市場から消えてくれれば今後はこうなりますな。

  • -moz-  …… Firefox
  • -webkit- …… Google Chrome、Safari、Edge、Opera
  • -o-    …… Opera
  • -ms-   …… Internet Explorer

FireFox(-moz-)とそれ以外(-webkit-)の世界。

※参考:そのベンダープレフィックス、いつまでつけてるの? - Qiita

ベンプレの何が辛いのか

いやー、それにしてもベンプレを付けるのは辛い作業。何がそんなに辛いのか・

例えばCSS3で追加されたグラデーション(linear-gradient())。

bg {
    background-image: linear-gradient(to bottom, #8BCC8E 0%, #A7F5AB 100%);
}

昔はCSSの背景色は1色ベタ塗りでグラデーションは画像を配置する必要があったが、これのおかげで画像なしでグラデーションの表現ができるようになった。とても助かる機能です。

しかしながら、この機能が追加された当初は対応ブラウザが少なくこんな書き方をしていた。

br {
    background-image: -webkit-gradient(
    linear,
    left top,
    left bottom,
    color-stop(0, #8BCC8E),
    color-stop(1, #A7F5AB)
    );
    background-image: -o-linear-gradient(bottom, #8BCC8E 0%, #A7F5AB 100%);
    background-image: -moz-linear-gradient(bottom, #8BCC8E 0%, #A7F5AB 100%);
    background-image: -webkit-linear-gradient(bottom, #8BCC8E 0%, #A7F5AB 100%);
    background-image: -ms-linear-gradient(bottom, #8BCC8E 0%, #A7F5AB 100%);
    background-image: linear-gradient(to bottom, #8BCC8E 0%, #A7F5AB 100%);
}

※参考:CSS Gradient Generator | CSS3 Factory

なんじゃこりゃあ!!*2

一番下にベンプレ無しのプロパティを書いているが、その上に「ベンプレなしのプロパティに非対応のブラウザは代わりにベンプレ付きの値の方を読んでね」と防衛策を打っているわけですな。(if文みたいなものですな)

いや、まあ、頭に-webkit-とか付けるだけならまだ単純作業なのでいいんですよ。コピペして接頭辞付けるだけなので。

ベンプレは何が辛いって修正が辛い!ベンプレ書いた分だけ何箇所も書き直さないといけないっ!!(しかも、種類によっては値の書き方も微妙に違うことがあるから注意が必要。。)

ベンプレを付けたくないがために未対応ブラウザを切り捨てたり、逆にその機能の対応を諦めたり、でも付けるのも辛い。不幸せの連鎖。。

ちなみに今はlinear-gradients()はほぼ全ブラウザ対応しているのでこんなに書かなくても大丈夫です。

※参考:Can I use... Support tables for HTML5, CSS3, etc

ベンプレはあくまでブラウザが正式対応してくれるまでの間の過渡期的な書き方なんですな。

ただし!IEは進化を止めてメンテナンスしかしない余生ブラウザなので機能追加は期待できない!!先の記事にもあるように、ベンプレを付けようが付けまいが全く対応してくれてない機能は動かない!

※参考:そのベンダープレフィックス、いつまでつけてるの? - Qiita

あと、CSS3とは無関係なブラウザ独自使用にはベンプレ必要な部分もあるようで、今後も完全になくなるわけではないようだ。

Autoprefixerのインストールの準備

案件によってはベンプレを付けてでもそのブラウザのユーザーに対応しよう、ということがどうしてもあるでしょう。そういった時に、手動ではなく自動でベンプレを付けてくれると嬉しい。

それを実現してくれるのが「Autoprefixer」らしい。そうだ Autoprefixerで 自動ベンプレ付けよう!

※参考:GitHub - postcss/autoprefixer: Parse CSS and add vendor prefixes to rules by Can I Use

早速インストールする。

まず、Node.jsとnpmは既に入っている前提(ターミナルで下記を叩くとバージョン番号が出る)

node -v
npm -v

Autoprefixerを入れるフォルダを作る。今回は「autoprefixer_test」とした。

cdコマンドでautoprefixer_testフォルダに移動。

cd (フォルダのパス)/autoprefixer_test

package.jsonの作成

npm init -y

ここまでいつもの流れ。

AutoprefixerはPostCSSのプラグインだった!

Autoprefixerというのは以前、「AltCSS」の記事で紹介した「PostCSS」のプラグインの一つらしい。(この記事では「NextCSS」というプラグインを使っている)*3

※参考:【LESS, SCSS, Sass, Stylus, PostCSS】 AltCSS 事始め - クモのようにコツコツと

PostCSSはプラグインを組み合わせてプロジェクトごとに最適な仕様にする、という思想。そのため、Sassなどの他のAltCSSとも競合せずに一緒に使うことができるらしい!

Sassの代わりではない

はい、これです。
この記事で言いたいことは、これがほぼ全てです。

僕は、PostCSSを、コンパイルしてCSSを生成するSassのようなものだと思っていました!
ですが、そもそもSassを使っていたので全くと言っていいほど必要性を感じてませんでした。

PostCSSというくらいなので、ポストプロセッサーとして、生成されたCSSに対して後処理をすることに使えます。
(導入するプラグインによっては、Sassのようなプリプロセッサー的な使い方も出来ます)

そのため、使い慣れているSassでコードを書きつつ、コンパイル後のCSSの最適化にPostCSSの様々なプラグインを使用するといったことが可能です!

※参考:SassとPostCSSを組み合わせて作るCSS開発環境 | Tips Note by TAM

これ、自分も全く同じ印象を持っていたのでビックリした!そうかー、Sassとかは「プリプロセッサー」でPostCSSは「ポストプロセッサー」。違うタイミングで実行できるから共用可能なんだ。

そのため、SassでコンパイルしたCSSにAutoprefixerでベンプレを付けるという使い方もできるわけだ。

Autoprefixerをインストール(Gulpで実行する)

Autoprefixerを実行する方法はいくつかあるようだ。

  • Gulp(タスクランナー)
  • Webpack(バンドルツール)
  • CSS-in-JS(ReactのようにJSのモジュールにHTMLもCSSも書く)
  • PostCSS CLI(PostCSSの実行環境)

※参考:GitHub - postcss/autoprefixer: Parse CSS and add vendor prefixes to rules by Can I Use

今回はこちらの記事を参考にGulpで実行できるようにしてみる。

※参考:CSSベンダープレフィックス-webkit-を今この瞬間に辞める為のAutoprefixerの導入 - Qiita

以下の3つのツールをローカルにインストールする。

  • gulp
  • gulp-postcss
  • autoprefixer

gulp-postcssがGulpでPostCSSを実行できるオプション

インストール!

npm i -D gulp gulp-postcss autoprefixer

`package.jsonに追記された!

  "devDependencies": {
    "autoprefixer": "^9.7.4",
    "gulp": "^4.0.2",
    "gulp-postcss": "^8.0.0"
  }

gulpfile.jsにAutoprefixerの設定を書く

フォルダ直下にgulpfile.jsを作成して、Autoprefixer設定を書く。

まず、先ほどのツールを読み込む。

const gulp = require("gulp");
const postcss = require("gulp-postcss");
const autoprefixer = require("autoprefixer");
  • 変数gulprequire()gulpを読み込み
  • 変数postcssrequire()gulp-postcssを読み込み
  • 変数autoprefixerrequire()autoprefixerを読み込み

Gulpの設定を書く。

gulp.task("default", function () {
  return gulp.src("src/test.css")
    .pipe(postcss([
      autoprefixer({
        browsers: [
            "last 2 versions", 
            "ie >= 11", 
            "Android >= 4"
        ],
        cascade: false
      })
    ]))
    .pipe(gulp.dest("benpre"));
});
  • gulp.task()でgulpの設定を書く。第一引数はdefault、第二引数は無名関数
  • 無名関数の中、returnで設定を返す。gulpの後にメソッドチェーンが続く
  • src()で対象ファイルを指定。srcフォルダの中のtest.css
  • 1つ目のpipe()の引数にpostcss()で、postcss()の引数は配列
    配列の値はautoprefixer()で、autoprefixer()の引数はオプションで連想配列
    連想配列の中、browsersオプションの値は配列
    配列の値はブラウザの設定。2つ前のバージョン、IE11以上、Android4以上
    cascadeオプションの値はfalse
  • 2つ目のpipe()の引数、gulp.dest()でファイルのエクスポート先を指定。benpreフォルダ。

cascadeオプションは公式サイトによると

cascade (boolean): should Autoprefixer use Visual Cascade, if CSS is uncompressed. Default: true

cascade(boolean):CSSが圧縮されていない場合、AutoprefixerはVisual Cascadeを使用する必要があります。 デフォルト:true

うーん、よくわかんない。。

こちらのサイトによると結果は基本的にtrueでもfalseでも同じだが、インデントの見栄えに違いがあるっぽい。

※参考:css - gulp-autoprefixerのカスケードオプション - プログラミングQ&A - BugInfo

以上の設定を書き終えると、ベンプレの付与がgulpで実行できるようになる。

npx gulp

(ローカルインストールのため、頭にnpxを加える。

Autoprefixer実行(真っ赤な注意書き。。)

フォルダ直下にtest.cssに先程のグラデ設定を書いてみる。

bg {
    background-image: linear-gradient(to bottom, #8BCC8E 0%, #A7F5AB 100%);
}

Autoprefixer実行!

npx gulp

むむっ、実行中になんだか真っ赤な注意書きが… f:id:idr_zz:20200216100317j:plain

  Replace Autoprefixer browsers option to Browserslist config.
  Use browserslist key in package.json or .browserslistrc file.

  Using browsers option can cause errors. Browserslist config 
  can be used for Babel, Autoprefixer, postcss-normalize and other tools.

  If you really need to use option, rename it to overrideBrowserslist.

  Learn more at:
  https://github.com/browserslist/browserslist#readme
  https://twitter.com/browserslist

なんぞこれ?翻訳すると

Autoprefixer browsersオプションをBrowserslist configに置き換えます。
   package.jsonまたは.browserslistrcファイルでbrowserslistキーを使用します。

   ブラウザオプションを使用すると、エラーが発生する可能性があります。 Browserslistの構成
   Babel、Autoprefixer、postcss-normalizeなどのツールに使用できます。

   本当にオプションを使用する必要がある場合は、BrowseBrowserlistをオーバーライドするように名前を変更します。

   詳細については:
   https://github.com/browserslist/browserslist#readme
   https://twitter.com/browserslist

browsersオプションはBrowserslistオプションに書き換えておくれと。

Browserslistオプションの詳細はこちら。 ※参考:GitHub - browserslist/browserslist: 🦔 Share target browsers between different front-end tools, like Autoprefixer, Stylelint and babel-preset-env

注意書きの下にはフィニッシュの文字が・

[10:02:09] Finished 'default' after 124 ms

一応、benpreというフォルダが作られて、中にtest.cssが書き出されている! しかし、Autoprefixerを実行するたびにこの赤い文字を見るのはあまり気分がよろしくないw

新しい書き方にも対応してみようかと。

browsersオプションをbrowserslistオプションに書き換えてみる

browsersオプションをbrowserslistオプションに書き換え、こちらの記事が参考になった!

※参考:webpackをアップデートしたらgulpfile.jsにautoprefixerの設定書いてるとエラー出るようになったのでpackage.jsonへ移動する │ 3oWebCreate WEB小ネタと生活ライフハック

まずgulpfile.jsbrowsersオプションを削除する。

gulp.task("default", function () {
  return gulp.src("src/test.css")
    .pipe(postcss([
      autoprefixer({
        browsers: [
            cascade: false
      })
    ]))
    .pipe(gulp.dest("benpre"));
});

オプションをpackage.jsonに移動してbrowserslistにリネイムしてみる

  "browserslist": [
    "last 2 versions", 
    "ie >= 11", 
    "Android >= 4"
  ]

Autoprefixer実行!

npx gulp

おお、今度はエラーが出ずに成功!

benpreフォルダの中のtest.cssはこうなった。

bg {
  background-image: -webkit-gradient(linear, left top, left bottom, from(#8BCC8E), to(#A7F5AB));
  background-image: -webkit-linear-gradient(top, #8BCC8E 0%, #A7F5AB 100%);
  background-image: linear-gradient(to bottom, #8BCC8E 0%, #A7F5AB 100%);
}

最初のベンプレの例に比べて、-webkit-のみでスッキリした!

browserslistオプションから固有のバージョンをなくしてみる

さらに、browserslistオプションの設定を変えてみる。こちらの記事の解説がわかりやすい!

※参考:Autoprefixerの対象ブラウザの選び方 | Rriver

まず、browserslistオプションは何も書かないとデフォルトではこんな設定らしい。

> 1%, last 2 versions, Firefox ESR

「1%以上のシェアのブラウザ、2バージョン前のブラウザ、最新のFirefox ESR版 」という意味になる。

AutoprefixerはCan I Use のブラウザ・サポート情報とStatCounterの全世界のブラウザ利用状況データを参照してBrowserslistの記述に当てはまるブラウザを抽出します。

ブラウザの対応状況を自動で見に行ってくれるのは嬉しい!我々の方ではバージョン番号の固有値を入れる必要がないということだ。

「Firefox ESR版」ってなんぞ?と思って調べると今のFirefoxは「Quantum」でESRは旧型らしい。

Firefox ESRの “ESR” は、Extended Support Releaseの略。
Mozillaが提供している、教育機関、公共機関など一括導入している法人に向け、延長サポートしている旧型のFirefoxだ。

※参考:「Firefox Quantum」と「Firefox ESR」 2匹の火狐を使い分ける!

Edgeに対するIEみたいな位置づけねw

先程の記事に戻ると、browserslistオプションの値がどのブラウザをカバーするかはこのサイトで確認ができる。

※参考:browserl.ist: A page to display compatible browsers from a browserslist string.

そんでもって%は世界のシェアなので日本限定にする場合はin JSを加える。

> 1% in JP, last 2 versions, Firefox ESR

うむ、IE10〜が対象になっているので、これで十分かな?

※参考:browserl.ist: A page to display compatible browsers from a browserslist string.

では、`packege.jsonを書き換える。JSONの形式にする。

  "browserslist": [
    "> 1% in JP",
    "last 2 version",
    "Firefox ESR"
  ]

Autoprefixer実行!

npx gulp

benpre/test.cssの実行結果。

bg {
  background-image: -webkit-gradient(linear, left top, left bottom, from(#8BCC8E), to(#A7F5AB));
  background-image: linear-gradient(to bottom, #8BCC8E 0%, #A7F5AB 100%);
}

お、-webkit-linear-gradient()がなくなった!この設定だと不要ということか。

最後に

ということで、人類を悩ませてきたベンプレ手動付与を自動化することができました!これはJSでいうBabel(ES6〜の記法をES5に変換する)のような位置づけに感じました。

Gulpで対象ファイルと実行ファイルを分けることで、対象ファイルの時はベンプレを全く気にせず、実行後にベンプレの値を変更することもありません。完全に切り分けられた世界です。

また、browserslistによって固有のバージョン番号ではなく相対的な%や世代を常に調べてくれるのもメンテナンスのしやすさを感じました!

CSSデバッグではもう一つやりたいテーマがあって、プロパティの書き順を自動でソートしたい。こちらも方法を調べています。それではまた!


※参考: qiita.com

*1:あまり使われてないけど自分はこの略しかた好きですw

*2:松田優作

*3:さらに、StyuleLintもPostCSSのプラグインなんだとか!知らずに使っているツールが他にもあるかも