Yeoman を使いつつ Bootstrap をカスタマイズしてみた


Bootstrap Components の実体
--------------------

Bootstrap は、これだけ使われているのに、jquery みたいに「プラグインの作り方」みたいな情報をあまり見ません。下記にある "Customizing components" というところも、既存の部品（CSSのクラス）の色とかサイズを少しいじった　という程度ですね。

http://getbootstrap.com/getting-started/#customizing

世の中、同じような疑問を持つヒトもいるようで、stackoverflow に下記のようなやりとりがありました。

http://stackoverflow.com/questions/12094928/how-would-i-create-twitter-bootstrap-components

>How would I create Twitter Bootstrap components?
>
>~(中略)~
>
Let's get our definitions straight. 'Component' is a CSS-styled element used in Bootstrap, such as a navbar, or a button group. 'Plugin' is a javascript plugin used to add behavior to a component. Sooo...which is it you're looking to create? –  jackwanders Aug 23 '12 at 15:27 

ざっくり言うと、CSSでの部品のひとかたまりがコンポーネントで、コンポーネントを組み合わせて UIの部品として jquery plugin化したものが プラグインといったところでしょうか。

今回は、下記の２つをやってみようと思います。

* デフォルトの Bootstrap の見た目を変更する
* もともとの Bootstrap にはない CSSの定義を作成する



前置き
-----

マジメに作るなら、たぶん下記の Bootstrap の Code Guide に従った方が良いんでしょうが、私自身はフロントエンジニアでもないので、今回は「とりあえず作ってみる」ってことで、気にせず行きます。

http://mdo.github.io/code-guide/




下準備
-----

まずは yeoman で 雛形作成。Bootstrap と Sass を有効にしてます。


```
$ yo webapp

     _-----_
    |       |
    |--(o)--|   .--------------------------.
   `---------´  |    Welcome to Yeoman,    |
    ( _´U`_ )   |   ladies and gentlemen!  |
    /___A___\   '__________________________'
     |  ~  |
   __'.___.'__
 ´   `  |° ´ Y `

Out of the box I include HTML5 Boilerplate, jQuery, and a Gruntfile.js to build your app.
[?] What more would you like? 
 ● Bootstrap
❯● Sass
 ○ Modernizr
```

で、とりあえず動かしておきましょう。

```
$ grunt serve
```

続いて、index.html からいらないものを削ってシンプルにしておきましょう。

全体の色を変更する
-----------

Bootstrap の見た目は、http://getbootstrap.com/customize/ にある Less Variables というところにある変数をいじると変わるようです。

今回構築した環境だと、Less ではなく、Sass になっているので、bower_components/bootstrap-sass-official/vendor/assets/stylesheets/bootstrap/_variables.scss の中で定義されているようですね。

で、そのあたりをいじるときっと変わる訳ですが、直接いじるのもナンなんで、bower_components/bootstrap-sass-official/vendor/assets/stylesheets/bootstrap.scss だけを下記のように変更してみました。

```scss:bootstrap.scss
// Core variables and mixins
// @import "bootstrap/variables";
@import "../../../../../app/styles/my-variables";
@import "bootstrap/mixins";
```

まるっと variables をコピーした上で、app/styles に _my-variables.scss を作成し、下記の変数を修正しました。ま、とりあえずわかりやすく色だけ変えたってところです。

```scss:_my-variables.scss
$brand-primary:         #71BCE9 !default;
$brand-success:			#B7D342 !default;
$brand-info:            #F9C14B !default;
$brand-warning:         #F09192 !default;
$brand-danger:          #CF142B !default;
```

で、index.html に下記のように追加してみると...

```html:index.html
    <div class="row marketing">
        <div class="col-lg-10 ">
            <div class="bgn-group btn-group-justified">
                <div class="btn-group">
                    <button type="button" class="btn btn-primary">Primary</button>
                </div>
                <div class="btn-group">
                    <button type="button" class="btn btn-success">Success</button>
                </div>
                <div class="btn-group">
                    <button type="button" class="btn btn-info">Info</button>
                </div>
                <div class="btn-group">
                    <button type="button" class="btn btn-warning">Warning</button>
                </div>
                <div class="btn-group">
                    <button type="button" class="btn btn-danger">Danger</button>
                </div>
            </div>
        </div>
    </div>
```

無事、色が変わりました :-) ボタンだけでなく、パネルなどにも無事反映されてます。

![buttons.png](https://qiita-image-store.s3.amazonaws.com/0/32059/d588708c-5014-6a28-780a-84cd1189b335.png "buttons.png")


ただし、上記の変更だけでテーマ全体が変更されるわけではなく、少なくとも、下記なども変更が必要になるみたいです。

```scss:_my-variables.scss
//== Form states and alerts
//
//## Define colors for form feedback states and, by default, alerts.

$state-success-text:             #3c763d !default;
$state-success-bg:               #dff0d8 !default;
$state-success-border:           darken(adjust-hue($state-success-bg, -10), 5%) !default;

$state-info-text:                #31708f !default;
$state-info-bg:                  #d9edf7 !default;
$state-info-border:              darken(adjust-hue($state-info-bg, -10), 7%) !default;

$state-warning-text:             #8a6d3b !default;
$state-warning-bg:               #fcf8e3 !default;
$state-warning-border:           darken(adjust-hue($state-warning-bg, -10), 5%) !default;

$state-danger-text:              #a94442 !default;
$state-danger-bg:                #f2dede !default;
$state-danger-border:            darken(adjust-hue($state-danger-bg, -10), 5%) !default;
```



コンポーネントに新しいCSSを追加する
--------------

次は、既存のCSSをいじるだけではなく、Bootstrap には用意されていないスタイルを作ってみましょう。

シンプルな例として、２つのボタンを固定サイズにしつつ、両端に配置したいようなケースを考えます。
単純に btn-group-justified を付けつつ、ボタンのサイズを固定にすると、下記みたいに配置されちゃうようです。btn-group-justified では、display: table を使っているんですね。

![btn-justified.png](https://qiita-image-store.s3.amazonaws.com/0/32059/a5a1fe55-5c25-6ff8-2474-9dce8badb76d.png "btn-justified.png")

```html:index.html
    <div class="row marketing">
        <div class="col-lg-10">
            <div class="bgn-group btn-group-justified my-btn-size">
                <div class="btn-group">
                    <button type="button" class="btn btn-primary">Cancel</button>
                </div>
                <div class="btn-group">
                    <button type="button" class="btn btn-primary">OK</button>
                </div>
            </div>
        </div>
    </div>
```

上記の状態に対して、追加すべきことは単純で、下記みたいなCSSを追加できればいいわけです。

```scss:main.scss
$my-margin: 10px;

.my-btn-both-end {
    .btn-group:nth-child(1) {
        .btn {
            margin-left: $my-margin;
        }
    }
    .btn-group:nth-child(2) {
        .btn {
            float: right;
            margin-right: $my-margin;
        }  
    }
}
```

こんな感じになりました。

![btn-bothend.png](https://qiita-image-store.s3.amazonaws.com/0/32059/708fed2c-4c96-ad44-37cc-1cdbceb99265.png "btn-bothend.png")


で、これらをまとめた btn-group-both-end というものを作ってみましょう。

@extend で btn-group-justified を引き継ぎつつ...

```scss:main.scss
$btn-width-both-end: 180px;
$btn-margin-both-end: 10px;

.btn-group-both-end {
    @extend .btn-group-justified;

// 見た目わかりやすいように...
    background-color: #E0E0E0;
    padding: 15px;
 
    .btn-group:nth-child(1) {
        .btn {
            width: $btn-width-both-end;
            margin-left: $btn-margin-both-end;
        }
    }
    .btn-group:nth-child(2) {
        .btn {
            width: $btn-width-both-end;
            float: right;
            margin-right: $btn-margin-both-end;
        }  
    }    
}
```

あれ？？

![btn-bothend-ng.png](https://qiita-image-store.s3.amazonaws.com/0/32059/8ce4bcb7-1c51-e4bf-beba-4bf76a01ad8a.png "btn-bothend-ng.png")


ちょっと調べてみたら、下記を見つけました。

http://www.culture27.com/blog/2011/07/sass_memo_4.php

> 気をつけること 1
> 
継承するのは@extendで指定したセレクタ自身のスタイルだけではなく、その子要素などのスタイルも継承するということです。

あぁ、実験くんで、btn-group-justified を含んだスタイル指定も　いろいろ同じHTMLに載せていたので、ごっちゃになっちゃったんですね。。そのあたりをうまく整理すれば、とりあえず使えるようになるかもしれませんが、メンテナンス不可能。。フロントの世界は、なかなか奥深い　というか　ダークというか、ややこしいですw

ということで、DRYではないけど、bower_components/bootstrap-sass-official/vendor/assets/stylesheets/bootstrap/_button-groups.scss にある .btn-group-justified からコピーしたパラメータをそのまま書けば OK です。もっといい方法がありそうだったけど、ちょっと探した範囲では見つかりませんでした。。

```scss:main.scss
.btn-group-both-end {
//    @extend .btn-group-justified; // ダメでした。。
//----- ここからコピー -----
    display: table;
    width: 100%;
    table-layout: fixed;
    border-collapse: separate;
    > .btn,
    > .btn-group {
        float: none;
        display: table-cell;
        width: 1%;
    }
//----- ここまでコピー -----

// 見た目わかりやすいように...
    background-color: #E0E0E0;
    padding: 15px;
 
    .btn-group:nth-child(1) {
        .btn {
            width: $btn-width-both-end;
            margin-left: $btn-margin-both-end;
        }
    }
    .btn-group:nth-child(2) {
        .btn {
            width: $btn-width-both-end;
            float: right;
            margin-right: $btn-margin-both-end;
        }  
    }    
}
```


まとめ
-----

フロントエンジニアではない私でも、Yeoman を使ってベースを作ってもらったことで、グダグダにならずに見た目のカスタマイズをきれいに出来た気がします。

ただ、@extend とか使って、Bootstrap の資産を活かして… と思っていたんですが、うまく出来ませんでした。

あと、CSSとかあんまり知らない人間が、Bootstrap をカスタマイズするなんて恐ろしい　と思っていたんですが、思ったよりも、カンタンにいろいろカスタマイズ出来そうです。