Rails で Bootstrap を使う gem「bootstrap-sass」を導入する

Rails アプリのレイアウト調整用に、bootstrap-sass という gem を入れてみる。

はじめに : Sass とか Scss とか Less とか何なの

これらはいずれも、CSS の拡張言語。ピュアな CSS ではまだやりたくてもできない、変数宣言や入れ子ルールなどが実現できる。Sass やら Less やらは、それを実現する言語の種類の違い。

他にも Stylus とか、最近は PostCSS とか何かよー分からんモノも色々あるけど気にしない。

bootstrap-sass という gem

今回は、Rails で使うなら Ruby ベースで親和性の高い Sass がいいだろう、ってな理由で、Sass を使う bootstrap-sass という gem を選定した次第。記法としては昔ながらの Sass 記法ではなく、よりピュアな CSS に近い Scss 記法で記載する。この gem で導入できる Bootstrap は Ver. 3系である (古いバージョンを指定すれば Ver. 2系の使用も可)。

Ver. 4系の Bootstrap を入れたい場合は、bootstrap という名前の gem が提供されている。インストール方法はこれから紹介する Ver. 3系とほとんど同じ模様。今後移行しやすいかも。ただ、現時点では Ver. 4系を急いで追っかけなくてもいいかなーという思いもあり、日本語の文献も多い Ver. 3系を選んだ。

ちなみに、Less を用いる Bootstrap の gem もある。less-railstwitter-bootstrap-rails という2つの gem を入れて使うようだ。Less には触れないので以下を参照。

bootstrap-sass をインストールする

インストール方法は公式の README.md が丁寧に書いている。これを噛み砕いて説明していく。

bootstrap-sass をインストールしたい Rails アプリの Gemfile に、以下を追記する。

gem 'sass-rails', '>= 3.2'
gem 'bootstrap-sass', '~> 3.3.6'

>= はそのバージョン以上の最新をインストール。~> はそのバージョン以上で、メインバージョンが上がらない範囲で最新をインストール、という書き方。

sass-rails の方は、Rails アプリを new した時点で Gemfile の上の方に既に書いてあるかもしれない。その場合は重複して書かないように。

Gemfile を書き換えたら、この定義ファイルの内容に従って gem をインストールするため、bundle install コマンドを打つ。

$ bundle install(中略)…
Using sass-rails 5.0.6
Installing bootstrap-sass 3.3.7
Installing autoprefixer-rails 6.7.7
…(中略)…

Bundle complete! 13 Gemfile dependencies, 58 gems now installed.
Use `bundle show [gemname]` to see where a bundled gem is installed.

とまぁこんな感じでインストールされる。

何やら勝手に autoprefixer-rails もインストールされた。bootstrap-sass が依存しているためか、勝手にインストールされたのだろう。これも Gemfile に書いておきたい便利 gem で、CSS でベンダプレフィックスをいちいち書かなくとも、Rails がコンパイル時に勝手にベンダプレフィックスを付与してくれるという gem なのだ。せっかくだから Gemfile に明記しておいて、念のため再度 bundle install しておこうか。

# Gemfile

# Autoprefixer Rails
gem 'autoprefixer-rails'
$ bundle install

Bundle complete! 14 Gemfile dependencies, 58 gems now installed.
Use `bundle show [gemname]` to see where a bundled gem is installed.

さっきので既に autoprefixer-rails もインストールはされているので「58 gems now installed.」の数字は変わらないが、Gemfile に明記したので「13 Gemfile dependencies」が「14 Gemfile dependencies」に変わっている。

インストール自体はコレでいいのだが、Bootstrap の CSS (厳密には Scss ファイル) と JavaScript (jQuery 依存しているスクリプト部分) を、Rails を通して読み込ませてやるための初期設定が必要になる。

Scss の初期設定

Rails アプリ全体で読み込まれる CSS は、app/assets/stylesheets/application.css というファイルに書くことになる。今回はコレを Scss 記法で書くため、ファイル名を application.scss にリネームする (application.css.scss としても OK)。

この中には、デフォルトでは以下のようなコメントが書かれている。

/*
 * This is a manifest file that'll be compiled into application.css, which will include all the files
 * listed below.
 *
 * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
 * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
 *
 * You're free to add application-wide styles to this file and they'll appear at the bottom of the
 * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
 * files in this directory. Styles in this file should be added after the last require_* statement.
 * It is generally better to create a new file per style scope.
 *
 *= require_tree .
 *= require_self
 */

このうち、

*= require_tree .
*= require_self

この *= で始まる2行は、実はコメントではなく、Rails が特別に解釈して動作する実処理の行なのである。

アセット・パイプライン

これは、書いた順に指定したアセット (資産の意・この場合はスタイルシートファイル) を読み込んでくれる「アセット・パイプライン」という仕組みで、Rails はこの仕組を使って CSS と JS を勝手にコンパイル・結合してくれるのだ。ザックリ言ってしまえば、Rails が用意している Browserify・Gulp・Webpack 的な仕組み、といったところか。

この application.scss と、後述する application.js は、他のファイルを読み込んでアプリ全体に適用していくので、「マニフェストファイル」と呼ばれている。

require というところから、まぁ何やら Import・Include 的なことをするのだなということは想像できると思う。具体的に treeself が何をしているのかは以下のとおり。

「なんだ、色々読み込んでくれるなら便利なんじゃん?」と思うが、Scss を使う場合はこの require を使ってはいけない。

Scss を使うなら require は使わない

sass-railsbootstrap-sass を導入し、Scss を使う場合は、この require を使わずに、@import という Scss の書式でマニフェストファイルを書く必要が出てくる。これは公式のインストール方法としても記載されている。

Then, remove all the *= require_self and *= require_tree . statements from the sass file. Instead, use @import to import Sass files.

Do not use *= require in Sass or your other stylesheets will not be able to access the Bootstrap mixins or variables.

require を使っても、他の .scss ファイルは正しく読み込んで結合してくれるのだが、変数やミックスインといった、Sass 独自の機能にアクセスできないという欠点がある (多分アセット・パイプラインは .scss ファイルを個別にコンパイルし、最後に Concat するのだろう。これだと変数のスコープが保てないのだと推測できる)。つまり、Bootstrap (bootstrap-sass) が用意している変数を参照したりできないのである。

そのため、Scss の機能を生かして他のファイルを読み込ませるために @import という記法を使うのである。

ではマニフェストファイルを書き換えよう

仕組みの話が長くなってしまったが、まずは先ほどの *= require で始まる行を削除する。コメントアウトとして残しておくのであれば、「=」を消して、* require_tree といったコメントとして残しておくと良いだろう。

そして、Bootstrap を使うには以下の2行の @import を書く。

// Bootstrap Sass
@import "bootstrap-sprockets";
@import "bootstrap";

必ず bootstrap-sprockets の方を先に書く。

なお、Scss の中では通常の CSS では使えない、//」で始まる1行コメントが書ける。JavaScript チックなコメントも書けるというワケだ。この1行コメントはコンパイル時に削除されるので、コンパイル後も残したいコメントは「/*! コメント */」と書くと良い。

全体としては、以下のように書き換えた。

/* 
 * This is a manifest file that'll be compiled into application.css, which will include all the files
 * listed below.
 * 
 * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
 * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
 * 
 * You're free to add application-wide styles to this file and they'll appear at the bottom of the
 * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
 * files in this directory. Styles in this file should be added after the last require_* statement.
 * It is generally better to create a new file per style scope.
 * 
 * require は使わない
 *   require_tree .
 *   require_self
 */

// Bootstrap Sass
@import "bootstrap-sprockets";
@import "bootstrap";

require@import と資産管理方法について

こうすると *= require_tree . しないんだからコントローラごとの CSS が読み込めないじゃないか~どうしたらええねん~、となるが、みんな資産の管理方法は色々悩んでいるようである。

一見便利なアセット・パイプラインだが、実は色んな問題があって、「少なくとも *= require_tree . は良くないよね」という流れになっている。

すなわち、配下の全ファイルを読み込むということは、無関係なコントローラ向けのスタイルも含んでいるし、その結合順序は保証されていないから、意図しないスタイルのカスケードが発生しうるということだ。ファイルサイズとしても重たくなるので、必要なページで必要なスタイルだけ読み込むべきだ、と。全ページに適用させるのは、こういう Bootstrap のような全体的なテーマだとか、Reset.css みたいなモノに限ろう、ということみたいである。

@import*= require_tree . みたいなことがしたいのであれば、app/assets/stylesheets/partials/ というディレクトリを作り、application.scss からは

@import "partials/*";

と書いて、配下の全ファイルを読み込ませることができる。

この辺は「こういうレールですよ!」という明確な決まりがないので、以下を参考にドウゾ。

JavaScript の初期設定

Scss の話が長くなってしまった。続いては Bootstrap が使用する JavaScript をマニフェスト・ファイルで読み込ませる。

app/assets/javascripts/application.js を開くと、デフォルトでは以下のような状態になっていると思う。

// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file. JavaScript code in this file should be added after the last require_* statement.
//
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require_tree .

先ほどの application.scss と同様に、この application.js の場合も「//= require_tree .」という一見コメントに見える行が、アセット・パイプラインの設定をしている。

このデフォルトの記述だと、下から4行分が require をしていて、jQuery → jQuery ujs (Rails が使うライブラリ) → Turbolinks (画面遷移を Ajax で行い高速化を図る Rails が用意した仕組み) → tree . すなわちその他のスクリプト、という順番で読み込んでいる。

Bootstrap の JS は jQuery を必要とするので、「//= require jquery」よりも後の行に、以下の1行を追加する。

// Bootstrap Sass
//= require bootstrap-sprockets

この辺の読み込み順の関係は、静的な HTML で Bootstrap を読み込む場合の script 要素の登場順と同じことである。

なお、ここで読み込ませるのは //= require bootstrap でも良い。違いは、Bootstrap のスクリプトファイルを個別に渡しているのが bootstrap-sprockets で、結合した1ファイルを渡しているのが bootstrap という違い。よく分からなければ上のままで。両方書いてはいけない。

bootstrap-sprockets and bootstrap should not both be included in application.js.

bootstrap-sprockets provides individual Bootstrap Javascript files (alert.js or dropdown.js, for example), while bootstrap provides a concatenated file containing all Bootstrap Javascripts.

初期設定完了!

長々と Rails でのアセット管理方法や仕組みについて絡めて書いてきたが、Rails アプリで Bootstrap を使うために必要なことを縮めると、以下にまとまる。

# Gemfile

gem 'sass-rails', '>= 3.2'
gem 'bootstrap-sass', '~> 3.3.6'
$ bundle install
// app/assets/stylesheets/application.scss

@import "bootstrap-sprockets";
@import "bootstrap";
// app/assets/javascripts/application.js

//= require jquery
//= require bootstrap-sprockets

これで Rails アプリの全ページに Bootstrap が適用されている。

試しに rails server でサーバを起動し、適当なページを開いてみよう。Bootstrap のデフォルトスタイルが適用されていることが確認できると思う。

もう少し HTML 側で設定

全体の HTML を定義している app/views/layouts/application.html.erb を開き、いくつか meta 要素を書いておこう。

<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<meta name="viewport" content="width=device-width, initial-scale=1">

Bootstrap の推奨テンプレートと同様に、ViewPort の設定とかをしておく。そういえば Rails の初期状態では charset 指定もないので追加しておいた。

あとは各 View の中で、各要素に Bootstrap の class を付与していけば Bootstrap デザインのできあがり。

<!-- たとえば一覧ページとかで… -->
<div class="container-fluid">
  <div class="table-responsive">
    <table class="table table-bordered table-hover">
      <!-- 省略 -->

こんな感じでレスポンシブルなテーブルのできあがり!

その他参考