特定のdiv要素の中だけBootstrapを適用する


独自のHTML/CSSで書かれたWebサイトで、「このdivの中だけBootstrapで書きたい」というケースがあったので、コレをどう実現しようかといろいろ奮闘したメモです。

## いろんな案

|アプローチ|Bootstrapの見た目|改修工数|
|---|---|---|
|普通のBootstrap を特定要素に適用する|"機能さえ絞れば" 再現性は高い|わりとカンタン|
|SassでカスタマイズしたBootstrap を特定要素に適用する|主要コンポーネントが細かく崩れやすい|ふつう|
|`<iframe>`を使う|その中だけなら完全にBootstrap|システム修正のほうがかかる|
|全部をBootstrapに置き換える|これが理想形|みんなが頑張る|

結論として最良は、*"全部Bootstrapにすること"* なんですけど、ここでは上2つについて。

## 普通のBootstrapを特定のdiv要素に適用する

コンパイル済みのBootstrapを使って、一部のdiv要素にBootstrapを適用するやり方です。子孫要素に適用するために Sass を使います。

### やり方

#### **1:** `bootstrap.css` を落としてくる

普通に [公式サイト](http://getbootstrap.com/getting-started/) から、Bootstrap のCSSを落としてきます。

#### **2:** おもむろに `_bootstrap.scss` にリネームする

拡張子をおもむろに scss に変更し、アンダーバーも追加して、Sassのpartialなコードとして解釈するようにしてあげます。

#### **3:** Sassで 子孫要素に `@import "bootstrap";` を置く

特定の要素の子孫要素として読み込みます。例えば `bootstrap` クラスの中で Bootstrap を適用するならこんな感じ。

```scss:main.scss
.bootstrap {
  @import "bootstrap";
}
```

#### **4:** コンパイルしてHTMLに読み込ませる

```html:example.html
...
<div class="normal">
  <h1>特定のdiv要素の中だけBootstrapを適用しようとした</h1>
  <p>ここはフツーのHTML</p>
</div>
<hr />

<!-- ここだけ Bootstrap -->
<div class="bootstrap">
  <div class="container-fluid">
    <div class="col-sm-6">
      <p>
        Partial bootstrap
      </p>
      <a href="#" class="btn btn-success">ここだけ Bootstrap</a>
    </div>
    <div class="col-sm-6">
      <p>
        グリッド
      </p>
    </div>
  </div>
</div>
```

やーん、カンタン。  
　  
　
...

#### **5:** 微修正

と思いきや、これだけだとちょっと見た目に違和感があります。

Bootstrap でスタイルが定義されている、 `<html>` 要素や `<body>` 要素は、絶対に `.bootstrap` の子孫要素に来ません。
そのため、それらの要素に反映されるはずの Bootstrap のスタイルが適用されていないのです。
（`bootstrap/scaffolding` のフォント/背景設定、 `bootstrap/normalized` のノーマライズ設定など）

この設定まで完璧に反映するなら、そのスタイルを`.bootstrap` に追加で適用します。

```scss
.bootstrap {
  // from bootstrap/normalized
  -ms-text-size-adjust: 100%;
  -webkit-text-size-adjust: 100%;

  // from bootstrap/scaffolding
  font-size: 10px;
  font-family: $font-family-base;
  font-size: $font-size-base;
  line-height: $line-height-base;
  color: $text-color;
  background-color: $body-bg;
  -webkit-tap-highlight-color: rgba(0,0,0,0);

  @import "bootstrap"
}
```

いろいろ足掻きましたが、どうも Sass で .bootstrap 下の html/body要素をピンポイントで継承する方法が見つからなかったので、bootstrap-sass の ソースコードを見ながら直指定してください。。。

もっと細かいことを言えば、

- Modal などの全画面前提なコンポーネントは、この親要素指定が影響して上手くスタイルが反映されなくなる可能性があります。
- グリッドは Media query によるものなので、要素幅ではなく**"画面幅"**でサイズが切り替わります。

そういう諸々を考えると、この方法は『機能さえ絞れば再現性は高い』という感じです。

## SassでBootstrapをカスタマイズした上でdiv要素に適用する

勿論、折角Sassを使っていることだし、Bootstrap自体をカスタマイズして、既存のWebデザインに合わせたい、という事もあると思います。

というわけで、同じ例を [bootstrap-sass](https://github.com/twbs/bootstrap-sass) でやってみた例が以下。`_customized-bootstrap.scss` がカスタマイズされたBootstrapです。

```scss:main.scss
.bootstrap {
  // html & body CSS from bootstrap/normalized (省略)
  // html & body CSS from bootstrap/scaffolding (省略)

  @import "customized-bootstrap"
}
```

```scss:_customized-bootstrap.scss
@import "bootstrap-variables";
@import "bootstrap";
```

```scss:_bootstrap-variables.scss
// please customize...
$font-family-sans-serif: 'Meiryo UI', 'メイリオ' , Meiryo , sans-serif;
```

### 結構CSSが反映されない部分が多い

おおむね良く動きますが、**コンポーネントが正しくスタイリングされない問題** はむしろ増えます。それも結構細かい所で。例えば `.container` の中にある Jumbotron の角丸が無いとか。

これらは主に **`&` セレクタ** が原因であることが多いです。例えば bootstrap-sass の `_jumbotron.scss` に、以下みたいな角丸の定義があるのですが...

```scss:_jumbtron.scss
.jumbotron {
  .container & {
    border-radius: 10px; // (例です)
  }
}
```

これがコンパイルされれば `.container .jumbotron` になってくれるのが普通。

が、今回は **親要素としてさらに別の要素がある** ため、`.container .bootstrap .jumbotron` と 真ん中にズケズケと `.bootstrap` が入ってしまい、CSSが適用されなくなってしまいます。うーん困る。

## 結論

### とりあえず...

独自デザインとフレームワーク、どっちを取るかって話にはなりますが、見た目を重視しない限りは、**迷ったらハジメっからBootstrap等のフレームワークで作った方が身のため** な気がします。

まぁ、この辺は現場感に応じてですね。思うように書き換えられないこんな世の中じゃ。POISON。