Gulp.jsとPostCSSを使ってCSSの面倒な作業をなくそう

Gulp.jsとPostCSSを使ってCSSの面倒な作業をなくそう

先生

先生

ここ最近はいろいろと勉強したいことがあふれかえってます。うまく時間を作って知識を増やしていきたいところです。こんにちは、CTOの林です。

近年のエンジニアリングは自動化の方向へどんどん流れています。
Grunt,Gulp,WebPack,CI,Chef,Ansible…… etc.

もちろんCSSにも自動化の流れが来ています。
過去にこんなことがありませんでしたか?

  • CSSのインデントや記述の仕方がバラバラ
  • パフォーマンス・チューニング??
  • とりあえずベンダープレフィックスを全部つけておけばいいだろう!
  • 圧縮を納品前にやって、圧縮したら崩れた

今日は普段の制作ですぐに使えるCSS自動化の方法を紹介しつつ、実際に使えるパッケージを導入するところまでを行いたいと思います。

※11月18日にいいオフィスで行われた「書籍『最強のCSS設計』出版記念イベント&勉強会―CSS設計、チーム開発を成功させるために必要なこと」で登壇したときの内容です。

CSSの自動化をしてみよう

自動化をする前の準備

自動化の第一歩としてGulpをインストールしましょう。
Gulpの動作にはNode.jsが必要なので、こちらをインストールし、以下のコマンドをターミナルまたはコマンドプロンプトで実行します。

Gulpをインストールします。

npm i -g gulp

gulp -vを実行してバージョンが表示されればインストールできています。

gulp -v
# CLI version 3.9.0

Gulp.jsについては入門記事の「Gulp.js入門 – コーディングを10倍速くする環境を作る方法まとめ」を書いていますので、CSS以外での活用部分を知りたい方はこちらもぜひご一読ください。

続いて、開発用のディレクトリを作成しましょう。

cd Documents/test
mkdir autocss
cd autocss

autocssというディレクトリを作りました。
そしてnpm initを実行してpackage.jsonを作成します。
ここで聞かれた内容は後で変更ができるので、とりあえずEnterを押していきましょう。

npm init

package.jsonには、環境構築に必要なパッケージが記録されていきます。
別のPCや他の人にも同じ環境を構築したい場合は、このpackage.jsonを共有すれば次回以降npm installを実行するだけで必要なパッケージがインストールされます。

Sassのコンパイル

複数のCSSをわかりやすく記述し、まとめていくためにSassを導入しましょう。
Sassの詳しい使い方は以下の記事をぜひご一読ください。

CSSを書くよりも効率的でわかりやすく記述することができます。

ここでは依存が少なく、Node.js単体で動作するgulp-sass(node-sass)を使います。

npm i gulp-sass --save-dev

gulpfile.jsというファイルを作成し、以下のように記述しましょう。

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

gulp.task('default', function () {
    return gulp.watch('*.scss',['css']);
});
gulp.task('css', function () {
    return gulp.src('*.scss')
        .pipe(sass())
        .pipe(gulp.dest('dest'));
});

そして以下のようなstyle.scssを作成し、gulp cssコマンドを実行してみましょう。

.test {
    .test-heading {
        font-size: 20px;
        font-weight: bold;
    }
    .test-content {
        padding: 10px;
    }
}
gulp css

するとdest/style.cssファイルが作成されました。

a {
  color: #ff290e; }

.test .test-heading {
  font-size: 20px;
  font-weight: bold; }

.test .test-content {
  padding: 10px; }

きちんとSassをコンパイルできました。続いてgulpコマンドを実行してみましょう。

gulp
# [19:23:53] Using gulpfile ~/Documents/test/autocss/gulpfile.js
# [19:21:49] Starting 'default'...
# [19:21:49] Finished 'default' after 13 ms

この状態でstyle.scssを変更してみましょう。

# [19:24:11] Starting 'css'...
# [19:24:11] Finished 'css' after 62 ms

と表示されて、dest/style.cssも更新されます。これでSassのコンパイルを自動化できましたね。監視はctrl(またはcommand)+cで終了できます。

Sass Lint

Sass LintはSassの記述をチェックするツールです。
あらかじめ設定ファイルを用意しておくことで、設定通りでない記述のときにはエラーまたは警告を表示します。まずは実際にインストールして試してみましょう。

SASS Lint

npm i gulp-sass-lint --save-dev

gulpfile.jsに以下の部分を追記します。

gulp.task('css', function () {
    return gulp.src('*.scss')
        .pipe(sassLint())
        .pipe(sassLint.format())
        .pipe(sassLint.failOnError())
        .pipe(sass())
        .pipe(gulp.dest('dest'));
});

続いて設定ファイルを作ります。.sass-lint.ymlというファイル名で以下の記述を丸々コピーして保存しましょう。

# sass-lint config generated by make-sass-lint-config v0.0.3
#
# The following scss-lint Linters are not yet supported by sass-lint:
# BemDepth, DisableLinterReason, ElsePlacement, PropertyCount
# PropertyUnits, SelectorDepth, SelectorFormat, SpaceAroundOperator
# TrailingWhitespace, UnnecessaryMantissa, UnnecessaryParentReference, Compass::*
#
# The following settings/values are unsupported by sass-lint:
# Linter Indentation, option "allow_non_nested_indentation"
# Linter Indentation, option "character"
# Linter NestingDepth, option "ignore_parent_selectors"
# Linter PropertySortOrder, option "ignore_unspecified"
# Linter PropertySortOrder, option "min_properties"
# Linter PropertySortOrder, option "separate_groups"
# Linter SpaceBeforeBrace, option "allow_single_line_padding"
# Linter VendorPrefix, option "identifier_list"

files:
  include: '**/*.scss'
options:
  formatter: stylish
  merge-default-rules: false
rules:
  border-zero:
    - 1
    - convention: zero
  brace-style:
    - 1
    - allow-single-line: true
  clean-import-paths:
    - 1
    - filename-extension: false
      leading-underscore: false
  empty-line-between-blocks:
    - 1
    - ignore-single-line-rulesets: true
  extends-before-declarations: 1
  extends-before-mixins: 1
  final-newline:
    - 0
    - include: true
  force-attribute-nesting: 1
  force-element-nesting: 1
  force-pseudo-nesting: 1
  function-name-format:
    - 1
    - allow-leading-underscore: true
      convention: hyphenatedlowercase
  hex-length:
    - 1
    - style: short
  hex-notation:
    - 1
    - style: lowercase
  indentation:
    - 1
    - size: 4
  leading-zero:
    - 1
    - include: false
  mixin-name-format:
    - 1
    - allow-leading-underscore: true
      convention: hyphenatedlowercase
  mixins-before-declarations: 1
  nesting-depth:
    - 1
    - max-depth: 3
  no-color-keyword: 1
  no-color-literals: 0
  no-css-comments: 0
  no-debug: 1
  no-duplicate-properties: 1
  no-empty-rulesets: 1
  no-extends: 0
  no-ids: 1
  no-important: 1
  no-invalid-hex: 1
  no-mergeable-selectors: 0
  no-misspelled-properties:
    - 1
    - extra-properties: []
  no-qualifying-elements:
    - 1
    - allow-element-with-attribute: false
      allow-element-with-class: false
      allow-element-with-id: false
  no-trailing-zero: 0
  no-transition-all: 0
  no-url-protocols: 1
  no-vendor-prefixes:
    - 0
    - additional-identifiers: []
      excluded-identifiers: []
  placeholder-in-extend: 1
  placeholder-name-format:
    - 1
    - allow-leading-underscore: true
      convention: hyphenatedlowercase
  property-sort-order: 0
  quotes:
    - 1
    - style: double
  shorthand-values:
    - 1
    - allowed-shorthands:
        - 1
        - 2
        - 3
  single-line-per-selector: 1
  space-after-bang:
    - 1
    - include: false
  space-after-colon:
    - 1
    - include: true
  space-after-comma:
    - 1
    - include: true
  space-before-bang:
    - 1
    - include: true
  space-before-brace:
    - 1
    - include: true
  space-before-colon: 1
  space-between-parens:
    - 1
    - include: false
  trailing-semicolon: 1
  url-quotes: 1
  variable-for-property:
    - 0
    - properties: []
  variable-name-format:
    - 1
    - allow-leading-underscore: true
      convention: hyphenatedlowercase
  zero-unit: 1

ではこの状態でgulp cssを実行してみましょう。

style.scss
   6:1  warning  Space expected between blocks  empty-line-between-blocks
  12:1  warning  Space expected between blocks  empty-line-between-blocks

6行目と12行目でwarningが表示されました。
これは{}の間に空行をはさみましょうという警告です。
かなり細かい警告ですが、Sass Lintを使うことでSass自体の書き方を統一させることができます。

しかし、これではさすがにルールとして厳しすぎるため、ルールを自分たちに合わせて変更していく必要があります。先ほどコピーして作った.sass-lint.ymlをテキストエディタで開いてください。

empty-line-between-blocksというワードを検索すると、

empty-line-between-blocks:
    - 1
    - ignore-single-line-rulesets: true

という箇所が見つかります。
ここに書いてある1がルールに従っていない場合はwarning(警告)を表示するという意味になります。0は表示しない、2はエラーという意味になります。エラーになった場合はgulpの処理自体がそこで停止するので、warningとうまく使い分けをしましょう。

ここでは0にして、gulp cssを再度実行してみましょう。

gulp css
# [19:32:13] Using gulpfile ~/Documents/test/autocss/gulpfile.js
# [19:32:13] Starting 'css'...
# [19:32:14] Finished 'css' after 211 ms

warningが表示されなくなりました。2とした場合は以下のようにエラーとなるので、どこまでを警告とし、エラーとするかを要件に合わせて調整していきましょう。

style.scss
   6:1  error  Space expected between blocks  empty-line-between-blocks
  12:1  error  Space expected between blocks  empty-line-between-blocks

✖ 2 problems (2 errors, 0 warnings)

詳しいLintの設定は以下にまとまっていますので、こちらを参考にしながら最適な設定にカスタマイズしましょう。

Sass Lint Rules

CSSO

次にCSSを圧縮、不要な記述を取り除くなどして軽量化/最適化していきましょう。
最適化には様々なパッケージがありますが、ここではコンパイル速度と圧縮率のバランスがよいgulp-cssoを使用します。さっそくインストールしてみましょう。

gulp-csso

npm i gulp-csso --save-dev

gulpfile.jsを以下のように書き替えます。

gulp.task('css', function () {
    return gulp.src('*.scss')
        .pipe(sassLint())
        .pipe(sassLint.format())
        .pipe(sassLint.failOnError())
        .pipe(sass())
        .pipe(csso())
        .pipe(gulp.dest('dest'));
});

そして、gulp cssを実行してみましょう。出力されたCSSを見てみると圧縮された形で出力されます。

a{color:#ff290e}.test .test-heading{font-size:30px;font-weight:700}.test .test-content{padding:10px}

このサンプルでは圧縮率はさほど変わりませんでしたが、例えば空の要素があった場合には削除されます。またpadding: 10px 10px 10px 10px;という記述があった場合にはpadding: 10px;に短縮され、容量を少しでも抑えることができます。

Sass Lintでもwarningが出るようになっているので、意識的に記述を変えるようにするか、自動化されるからLintはいらない場合は.sass-lint.ymlを修正したりして調整をしましょう。

LIGはWebサイト制作を支援しています。ご興味のある方は事業ぺージをぜひご覧ください。

Webサイト制作の実績・料金を見る

この記事のシェア数

CTOの林です。フロントエンドを専門とし、AngularJSのコミュニティをはじめ、様々な勉強会に顔を出しています。効率化マニアでGrunt,Gulpをはじめ、プロジェクト進行やサーバーサイド、インフラ周りの効率化を目指し日々活動しています。 【役職紹介 / CTO】 Web制作にかかる内容を統括しています。プロジェクトを横断的に見渡し、技術的な見地からアドバイスなどを行い、ときには実制作のヘルプを行ったりしています。新人エンジニアの育成や、体外的な活動としてLIG全体のエンジニアのブランディングのため勉強会やイベントへの登壇・開催なども行っています。 【普段やっていること】 新規サービスの設計(UI,遷移,DB,APIなど)、エンジニアの育成及び環境整備、技術選定、Web制作ユニットの統括とプロジェクト進行を円滑にするための仕組みづくり、フロントエンド周りの実装、エンジニアリングの開発効率化、勉強会の登壇・主催など

このメンバーの記事をもっと読む