Yii で bootstrap-sass を使う

bootstrap-sass がいい感じだったので Yii 1.x で試してみました。Bootstrap 3 が使える Yii の拡張として [yii-bootstrap3-module](http://www.yiiframework.com/extension/yii-bootstrap3-module/) や [yiistrap](http://www.yiiframework.com/extension/yiistrap) などがあるみたいですが、この記事では yiistrap を使って解説していきます。

## 用意しておくもの

以下のものが必要になります。

- composer
- Ruby
- bundler
- sass
- compass
- bootstrap-sass

OS X などのシステムで標準に入っている Ruby を使う場合は sudo が必要だったりするので注意してください。Windows の場合は何からの形で Ruby をインストールしておいてください。

とりあえず bundler をインストールし、プロジェクトルートに移動後 composer もインストール

```console
gem install bundler
cd path/to/project
curl -sS https://getcomposer.org/installer | php
```

## composer で Yii と yiistrap をインストール

今現在 yiistrap は master ブランチからインストールすると bootstrap 2 になるので bs3 ブランチを指定してインストール。あと、yiistrap/bs3 を composer でインストールすると bootstrap 3 もインストールされちゃうので、 replace で除外します。

```js:composer.json
{
    "require": {
        "yiisoft/yii": "~1.1",
        "crisu83/yiistrap": "dev-bs3"
    },
    "replace": {
        "twbs/bootstrap": "*"
    },
    "config": {
        "preferred-install": "dist",
        "vendor-dir": "protected/vendor"
    }
}
```

composer.json を用意したらインストールコマンドを実行し、ついでに yiic webapp もやっておく。

```console
php composer.phar install
./protected/vendor/bin/yiic webapp .
```

## bootstrap-sass をインストール

bootstrap-sass のインストール方法は [twbs/bootstrap-sass](https://github.com/twbs/bootstrap-sass#installation) を参考にして Compass から使う形にしました。

Gemfile の作成

```console
bundle init
```

Gemfile というファイルが作成されたら必要な gem を追加していきます。

```rb:Gemfile
source 'https://rubygems.org'

gem 'sass'
gem 'compass'
gem 'bootstrap-sass'
```

以下で gem をインストール。yii にも protected 以下に vendor ディレクトリがあるので、そこへ強引にインストールする形にしました。

```console
bundle install --path protected/vendor/bundle
```

最後に compass の bootstrap を利用する形で create コマンド実行。css, image, javascript などのディレクトリは yii webapp で生成されたディレクトリ名に合わせるようにする。

```console
bundle exec compass create -r bootstrap-sass --using bootstrap --css-dir "css" --images-dir "images" --javascripts-dir "js"
```

## Yii のレイアウト、ビューの修正

yiistrap を使えるように index.php に以下を追加 (機能テストする場合は index-test.php にも)

```php:index.php
require dirname(__FILE__) . '/protected/vendor/autoload.php';
```

protected/components/Controller.php を修正

```php:Controller.php
class Controller extends CController
{
    public $layout = '//layouts/main';
    ...
```

/protected/views/layouts/main.php を修正


```html+php:main.php
<?php /* @var $this Controller */ ?>
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title><?php echo CHtml::encode($this->pageTitle); ?></title>
    <link rel="stylesheet" href="<?php echo Yii::app()->baseUrl; ?>/css/styles.css">
    <?php Yii::app()->clientScript->registerPackage('jquery'); ?>
    <!--[if lt IE 9]>
        <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
        <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
    <![endif]-->
</head>
<body>
<?php $this->widget('\TbNavbar',array(
    'brandLabel' => CHtml::encode(Yii::app()->name),
    'display' => null,
    'items' => array(
        array(
            'class' => '\TbNav',
            'items' => array(
                array('label' => 'Home', 'url' => array('/site/index')),
                array('label' => 'About', 'url' => array('/site/page', 'view' => 'about')),
                array('label' => 'Contact', 'url' => array('/site/contact')),
                array('label' => 'Login', 'url' => array('/site/login'), 'visible' => Yii::app()->user->isGuest),
                array('label' => 'Logout ('.Yii::app()->user->name.')', 'url' => array('/site/logout'), 'visible' => !Yii::app()->user->isGuest)
            ),
        ),
    ),
)); ?>
<div class="container">
    <?php if (isset($this->breadcrumbs)): ?>
        <?php $this->widget('\TbBreadcrumb', array(
            'links' => $this->breadcrumbs,
        )); ?>
    <?php endif; ?>

    <?php echo $content; ?>
    <hr>

    <footer class="footer text-center">
        Copyright &copy; <?php echo date_create()->format('Y'); ?> by My Company. All Rights Reserved. <?php echo Yii::powered(); ?>
    </footer>
</div>

<script src="<?php echo Yii::app()->baseUrl; ?>/js/bootstrap.js"></script>
</body>
</html>
```

通常 yiistrap は Yii::app()->bootstrap->register(); を追加して css, js のファイルを上手く呼び出してくれるみたいですが、bootsrap-sass が間に入ってしまうため、上記のような形で直接指定する形を取りました。あと、細かなことを言えば js ファイルはできるだけ 1 ファイルにまとめて圧縮後 body の閉じタグ直前に書いておくほうがいいかもしれません。

ウィジェットなどを使う場合は [Yiistrap Widgets](http://www.getyiistrap.com/site/widgets) のパスエイリアスを取り除いてバックスラッシュに置き換えると上手く読み込んでくれます。

## bootstrap-sass を使って css をカスタマイズ

一番簡単なのは sass/_bootstrap-variables.scss 内の変数を好みの値に置き換える方法です。たとえば、サイトのメインカラーを変更したい場合は $brand-primary を探してコメントを取り除き、以下のようにし、コンパイルを実行します。

```scss:_bootstrap-variables.scss
$brand-primary: #f27242;
```

```console
compass compile
```

ボタン (.btn-primary を指定したもの) の背景色やリンクがオレンジ色に変わっているかと思います。その他、グリッドをデフォルトの 12 から 24 にしてみたり、.container の幅を調整してみたり、border-radius を控えめにしてみたり、いろいろ調整が効くので、これだけでも見た目を随分と変えることができます。

あとは sass/styles.scss に以下を追加して、bootstrap を拡張した独自のセレクターを追加したりもできます。bootstrap の変数、@extend などを利用できるので、柔軟なカスタマイズが可能になります。

```scss:_bootstrap-custom.scss
@import 'bootstrap-custom';
```

## サンプル

以下は、適当に変数の値を調整後のログイン画面の雰囲気です。

```scss:_bootstrap-variables.scss
$gray-light: lighten(#000, 46.7%);
$brand-primary: #f27242;
$text-color: $gray-light;
$font-family-sans-serif: "Lucida Grande", "Hiragino Kaku Gothic ProN", Meiryo, sans-serif;
$border-radius-base: 2px;
$border-radius-large: 3px;
$border-radius-small: 1px;
$screen-md: 592px;
$grid-gutter-width: 30px;
$container-large-desktop: ((650px + $grid-gutter-width));
$container-lg: $container-large-desktop;
$navbar-default-bg: #fff;
$navbar-default-link-active-bg: darken($navbar-default-bg, 3.5%);
```

```html+php:login.php
<?php $this->pageTitle = Yii::app()->name . ' - Login'; ?>
<?php $this->breadcrumbs = array('Login'); ?>

<h1>Login</h1>

<div class="row">
    <?php $form = $this->beginWidget('\TbActiveForm'); ?>
    <div class="col-md-6">
        <?php echo $form->textFieldControlGroup($model, 'username'); ?>
        <?php echo $form->passwordFieldControlGroup($model, 'password'); ?>
        <?php echo $form->checkBoxControlGroup($model, 'rememberMe'); ?>
        <?php echo TbHtml::submitButton('Login', array('color' => TbHtml::BUTTON_COLOR_PRIMARY)); ?>
    </div>
    <?php $this->endWidget(); ?>

    <div class="col-md-6">
        <p>Hint: You may login with<br>
        <kbd>demo</kbd>/<kbd>demo</kbd> or <kbd>admin</kbd>/<kbd>admin</kbd>.</p>
    </div>
</div>
```
![yiistrap-view-login.png](https://qiita-image-store.s3.amazonaws.com/0/11524/7a464505-ae4c-a473-b964-1c850b130b20.png)

## 参考リンク
- [GitHub crisu83/yiistrap/bs3](https://github.com/crisu83/yiistrap/tree/bs3)
- [GitHub twbs/bootstrap-sass](https://github.com/twbs/bootstrap-sass)
- [Bootstrap 3 Sassの使い方 | Webエンジニアブログ](http://dim5.net/css-framework/bootstrap3-sass-customize.html)