脱Bootstrapガイド 〜フルスクラッチCSS〜


![スクリーンショット 2015-11-06 0.22.23.png](https://qiita-image-store.s3.amazonaws.com/0/32596/846d85ea-6fa6-37f5-521d-cc87501fe1f1.png "スクリーンショット 2015-11-06 0.22.23.png")

# 2021/02/12 追記

この記事を執筆した当時、Bootstrapがどのサイトでも使われていました。
当時のBootstrapはjQueryと密結合していたり、いろいろと剥がす動機があったのですが、
現在のBootstrapは内部的にもflexboxになっていたりと改良されています。
まずは剥がす前に最新版への更新を検討してみてください。

https://getbootstrap.jp/

一方で、TailwindやインラインスタイルCSSなど、Bootstrapを採用しづらい場面も増えてきています。
その場合にはやや記述は古いのですが本記事が役に立つ場面もあるでしょう。
ポイントは、腹をくくってFlexboxのプロパティについて真剣に学ぶことです。

**追記終わり**

Bootstrapは便利ですし、デフォルトのスタイルもフラットでかっこいいですね。
デザイナーでなくてもそれなりに整った画面が作れるということで、大変便利なBootstrapですが、
私は何でもかんでもBootstrapを使ってしまって、Bootstrapなしではレイアウトが組めないようになってしまっていました。

というわけで、この記事ではCSSの修行も兼ねてフルスクラッチで行けるところまで行ってみよう、というテーマで書き始めました。

レイアウト周りの実装はほとんど[Solved by Flexbox](https://philipwalton.github.io/solved-by-flexbox/)が元ネタです。
執筆に先立ち、勉強のために[Solved by Flexbox和訳版](http://hashrock.github.io/solved-by-flexbox-ja/)を作成しました。詳細が気になる方は、こちらもご参照ください。

# Bootstrapのいいところ、微妙なところ

Bootstrapは導入するだけで下記のような利点があり、プログラマーのみならずデザイナーの方でも使っているという方も多いでしょう。

* 色彩センス不要
* レスポンシブ対応
* アイコンが揃っている
* デフォルトでフラットデザイン
* きれいなフォーム（縦位置を揃えるのは本当に大変）
* ダイアログやタブなどのコンポーネントも便利

一方、下記のような難点もあります。

* コンポーネントがjQuery依存（SPA勢には辛い）
* 見た目に関するクラス指定がHTML全体に蔓延する（例：btn btn-defaultがすべてのボタンに指定されている、etc...）

そこで、CSSフルスクラッチで書き直すと、下記のようないいことがありますね。

* **CSSの量が減る**
 * minifyいらず
 * 見通しが格段に良くなる
 * 高速化も期待できる
* HTMLがシンプルになる
* ブラウザの進歩にあわせて、今後もCSSを削っていける
* CSSフレームワークとの密結合を回避できる

# Bootstrapを取り除く前に

Bootstrapからの移行作業は、HTMLの構造まで手を入れることになるため、結構な重労働となります。
そこで、Nightmareやwebdriverioなどを使って、ページのスクリーンショットGIFを自動生成することをおすすめします。
初期に確認作業の半自動化ができると、はまった際のモチベーションの低下を軽減できます。

参考：[NightmareでE2Eテストしつつスクリーンショットとってgifに結合したら目視チェックが最高に楽になった](http://qiita.com/mizchi/items/04c53e17ed5c4ec7e8d7)


# 初期化方針

[Sanitize.css](https://10up.github.io/sanitize.css/)など、お好みのCSSリセットを適用してください。

個人的なおすすめはBootstrap版リセットCSSの[Reboot](https://v4-alpha.getbootstrap.com/content/reboot/)です。システムフォントが使われるなどの注意点はありますが、フォーム要素に対しての最小限のスタイル指定がされている、マージン設計面で参考になる点が多いなど、自前でCSSを構築するベースとして良いと考えています。

CSSリセットを使わない場合でも、`box-sizing: border-box;`は全要素に指定したほうがいいでしょう。
後述のグリッドシステムが崩れる原因となります。

また、文字サイズ指定はhtml要素に指定します。remはhtml要素から計算されます。

```css
*, *:before, *:after {
	box-sizing: border-box;
}
html{
	font-size: 16px;
}
```


# グリッドシステム

Bootstrapのグリッドシステムは、親となる「rowクラス」内部を水平に12分割するグリッドを作ります。

![スクリーンショット 2015-11-06 0.06.17.png](https://qiita-image-store.s3.amazonaws.com/0/32596/1cbf59f0-20d8-d17c-f9b0-3f82c7517b3a.png "スクリーンショット 2015-11-06 0.06.17.png")

この方式は自由度が高く、12分割のグリッドに沿う形であれば、いろいろな比率でボックスを配置することができます。

しかし、実際のところ、ここまで複雑なレイアウトには滅多にお目にかかりません。
もっとよく見るのは、下図のようなレイアウトでしょう。


![スクリーンショット 2015-11-06 0.10.01.png](https://qiita-image-store.s3.amazonaws.com/0/32596/e3ca8e69-1ea0-e69f-5584-49a9f4af0d5f.png "スクリーンショット 2015-11-06 0.10.01.png")

せいぜい２〜３分割、または等分レイアウトを使っています。
また、カード風のレイアウトをスマホのような小さいスクリーンで見た場合、縦に並ぶのもお決まりですね。

こういったよく使われるケースに限れば、グリッドシステムの実装を単純化することができそうですね。


## flexboxで３分割（レスポンシブ対応）

小さい画面ではフル幅になり、そうでない場合は３つずつ並べていくレイアウトを行ってみましょう。

![スクリーンショット 2015-11-06 2.27.09.png](https://qiita-image-store.s3.amazonaws.com/0/32596/ca53b331-c22e-d4ce-40b7-a1a427cf071d.png "スクリーンショット 2015-11-06 2.27.09.png")

基本的なグリッド実装は下記の通りです。

```html
<div class="feature-list">
  <div class="feature-item">…</div>
  <div class="feature-item">…</div>
  <div class="feature-item">…</div>
</div>
```

```css
.feature-list {
  display: flex;
  flex-wrap: wrap;
}

.feature-item {
  flex: 0 0 33.3333%;
  max-width: 33.3333%; /* IE11バグ対応 */
}
```

表示例：

![スクリーンショット 2015-11-06 2.39.30.png](https://qiita-image-store.s3.amazonaws.com/0/32596/7cd6e621-6a67-8b53-a512-737e7937d084.png "スクリーンショット 2015-11-06 2.39.30.png")

もちろん、marginとpaddingを活用することで、隙間のあるレイアウトも可能です。

![スクリーンショット 2015-11-06 2.52.42.png](https://qiita-image-store.s3.amazonaws.com/0/32596/9c68c8bc-5df7-81b3-948f-babdae0db32a.png "スクリーンショット 2015-11-06 2.52.42.png")

実装詳細は[デモ](http://hashrock-sandbox.github.io/byebye-bootstrap-example/page1.html)のソースを参照してください。

レスポンシブ対応は、単純にメディアクエリを使います。
下記は、800px以下の場合はfeature-itemは最大幅に拡張します。

```css
@media (max-width: 800px) {
  .feature-item {
    flex: 0 0 100%;
    max-width: 100%; /* IE11バグ対応 */
  }
}

```

また、スマホでPCサイトが表示されないよう、初期倍率を指定する必要があります。head内に下記の記述を追加します（よく見る[maximum-scale等は指定しない](http://blog.ousaan.com/index.cgi/links/20130925.html)）。

```html
<meta name="viewport" content="width=device-width, initial-scale=1.0">
```




表示例（800px以下の時）：

![スクリーンショット 2015-11-06 2.40.00.png](https://qiita-image-store.s3.amazonaws.com/0/32596/f3e02b34-4096-69af-54a8-8e789b774e36.png "スクリーンショット 2015-11-06 2.40.00.png")

以上のデモはこちらです：

http://hashrock-sandbox.github.io/byebye-bootstrap-example/page1.html

追記(2016/02/15)：

IE11では、flex-basisがborder-box利用時に正常に計算されないバグがあり、max-widthを同時に指定する必要があります。詳しくは下記ページを参照して下さい。

[【IE11バグ】 flex-basisにbox-sizingが効かない不具合 – 広告のフジプロ](http://www.fujipro-inc.com/2015/11/30/2910.html)



## flexboxで２ペインまたは３ペインレイアウト

こちらも良くある、ナビゲーションの幅を固定して、中央のコンテンツはウィンドウ幅に応じて収縮するパターンですね。

![2カラム](https://qiita-image-store.s3.amazonaws.com/0/32596/fda41f08-5d7b-f475-1f74-2b6103f30622.png)
![3カラム](https://qiita-image-store.s3.amazonaws.com/0/32596/59037052-1a6e-a299-f57d-632fb365b13a.png)

この実装に関しては、別記事を起こしていますので、こちらをご参照ください。

[floatより辛くない「flexbox」でざっくりレイアウト - Qiita](https://qiita.com/hashrock/items/939684b9207dbab1d59e)

**2017-12-11追記:**

下記にも書きましたが、大まかに画面を分割するようなレイアウトは、IE11やiOS10.2を外せるのであればGrid Layoutを使うのが現在の推奨です。

[floatより辛くない「flexbox」でざっくりレイアウト](https://qiita.com/hashrock/items/939684b9207dbab1d59e#20171206%E8%BF%BD%E8%A8%98)

# フォーム

下記のようなタイプのフォームは、flexboxで実装することが可能です。詳しくは[Solved by flexbox当該記事](http://hashrock.github.io/solved-by-flexbox-ja/demos/input-add-ons/)を参照してください。

![スクリーンショット 2015-11-06 2.59.00.png](https://qiita-image-store.s3.amazonaws.com/0/32596/e137bca1-76d4-7c70-fecb-60b960be8f4f.png "スクリーンショット 2015-11-06 2.59.00.png")


# ボタン

![スクリーンショット 2015-11-06 1.19.14.png](https://qiita-image-store.s3.amazonaws.com/0/32596/7ed18a45-fbbf-ec37-db1e-fec14356bce5.png "スクリーンショット 2015-11-06 1.19.14.png")

ここのところ、ゴーストボタン（枠線のみのボタン）スタイルが流行っています。どうも流行がループしてるんじゃないか疑惑がありますが…。

フラットスタイルボタンよりもさらに軽やかな感じがあるため、まだ数年は使われる気がします。
また、CSSでの実装がこれ以上ないくらいに簡単なのがいいですね。というわけでBootstrapデフォ風のフラットボタンではなくて、ゴーストボタンでいきましょう。

サクッと自前実装したのが、下記のものです。

![スクリーンショット 2015-11-06 3.10.55.png](https://qiita-image-store.s3.amazonaws.com/0/32596/99b2cdc2-754e-2c23-44b6-7502359d1c28.png "スクリーンショット 2015-11-06 3.10.55.png")

```css
.ghost-button{
	background: #333;
	color: white;
	border: 1px solid gray;
	border-radius: 4px;
	cursor: pointer;
	text-decoration: none;
	padding: 1rem;
	outline: none;
}

.ghost-button--round{
	border-radius: 100px;
}

.ghost-button:hover{
	background: #444;
}
```

特に難しい部分はないですね。

個人的には、そもそもボタン自体の利用を控えるべきではないかと感じています。
ボタンを置きたくなった時に、下記の点について一旦考えてみるのもいいかもしれません。

 * ボタンではなく、リンクで十分ではないか？
 * ボタンを押した後、何が起こるかをユーザは想像できるか？
 * ボタンではなく、ドラッグのような、オブジェクトの直接操作で代替できないか？
 * ユーザがボタンを押す必要が本当にあるか？（例：保存ボタンは自動保存機能があれば不要）


# アイコン

Bootstrapには~~fontawesome~~ [Glyphicons](http://glyphicons.com/) が同梱されており便利ですが、
ロゴのフォントを選ぶのと同様に、アイコンのスタイルにもいろいろあるので、サイトのテイストと合わせて選ぶのがいいかと思います。

## フォーマットについて

IE8を切り捨てられるのであれば、もうWOFF形式だけでいいようです。

http://caniuse.com/#feat=woff

### Simple Line Icons Webfont

線で構成されていて軽い感じです。

http://graphicburger.com/simple-line-icons-webfont/

![スクリーンショット 2015-11-06 3.26.00.png](https://qiita-image-store.s3.amazonaws.com/0/32596/0426b920-d914-4dc6-359a-01b1ec7923a3.png "スクリーンショット 2015-11-06 3.26.00.png")

### Typicons

丸っこくてかわいい感じ。

http://typicons.com/

![スクリーンショット 2015-11-06 3.29.20.png](https://qiita-image-store.s3.amazonaws.com/0/32596/8aaa3abf-42a8-c173-1f98-e34b2847723c.png "スクリーンショット 2015-11-06 3.29.20.png")

### Genericons

シュッとしています。

http://genericons.com/

![スクリーンショット 2015-11-06 3.32.17.png](https://qiita-image-store.s3.amazonaws.com/0/32596/c20b59b5-83b0-a2f6-be9b-eb35f66ad34b.png "スクリーンショット 2015-11-06 3.32.17.png")

### Foundation Icon Fonts 3

これも硬い感じ。

http://zurb.com/playground/foundation-icon-fonts-3
						
![スクリーンショット 2015-11-06 3.35.13.png](https://qiita-image-store.s3.amazonaws.com/0/32596/7138b4f4-1df9-a47d-6b34-ecc199a91974.png "スクリーンショット 2015-11-06 3.35.13.png")

### Fontello

http://fontello.com/

複数のアイコンフォントから、使うアイコンだけを選択してWebFontを作成できるサイトです。
ロード時間を最小化するために便利かと思います。

### Bytesize

https://danklammer.com/bytesize-icons/

![スクリーンショット 2017-12-11 11.18.08.png](https://qiita-image-store.s3.amazonaws.com/0/32596/d5e16fe8-3967-1147-7097-441cee71773c.png)


すこし変わり種で、インラインSVGを使ってアイコンを表示するものです。３行程度のコードスニペットをHTMLに貼り付けるだけでアイコンを表示できます。

例えばCloseアイコンは下記のような感じです。

```html
<svg id="i-close" viewBox="0 0 32 32" width="32" height="32" fill="none" stroke="currentcolor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2">
    <path d="M2 30 L30 2 M30 30 L2 2" />
</svg>
```

viewboxに応じて自動でリサイズされるため、サイズを調整するには、widthとheightを変えるだけでOKです。
また、上記スクリーンショットでは線の角が丸いスタイルですが、SVGなので、線を角ばらせたり、線の色や太さを変えることが出来ます。
HTMLが汚れるという弱点もありますが、アセットも削減できるので一押しです。

# その他UIパーツ

Flexbox Patternsというサイトが、UIパーツのFlexbox実装例として参考になります。

http://www.flexboxpatterns.com/

下記はタブ、ヘッダ、サイドナビゲーションの例ですが、他にもそのまま使えそうなおしゃれなデザインのUIが掲載されていますので、ぜひ参照してみてください。

![スクリーンショット 2016-02-15 13.17.11.png](https://qiita-image-store.s3.amazonaws.com/0/32596/1146f800-6025-4a13-f50e-b12525a64dce.png)
![スクリーンショット 2016-02-15 13.17.19.png](https://qiita-image-store.s3.amazonaws.com/0/32596/6fdd0fbf-d4b9-fed3-81ad-ca422a1f34bc.png)
![スクリーンショット 2016-02-15 13.17.36.png](https://qiita-image-store.s3.amazonaws.com/0/32596/d8673110-9f5b-1f92-4751-b0802af43aa5.png)

# その他、参考になりそうな薄いCSSフレームワーク

 * [Marx](https://github.com/mblode/marx)
 * [Rin](http://memo.sanographix.net/post/111271001195)
 * [Bulma](http://bulma.io/)

# 追記：flexboxのバグに立ち向かう

IE11や、Safariで顕著ですが、ブラウザ実装にバグが存在します。例えば、下記のような問題が報告されています。

 * flexアイテムの最小コンテンツサイズが順守されない(safari)
 * align-items:center に設定された縦並びのflexアイテムが、親コンテナからはみ出してしまう(IE11)
 * flexコンテナの min-height が内包するflexアイテムに適用されない(IE11)
 * 省略記法のflex 定義で、flex-basis に単位のない値を指定すると無視される(IE11)
 * 縦並びのflexアイテムが、本来のアスペクト比を保持してくれない(IE11)
 * flex のデフォルト値が仕様と違う(IE11)
 * flex-basis の計算が box-sizing:border-box を考慮していない(IE11)
 * flex-basis が calc() をサポートしていない(IE11)
 * 幾つかの HTML 要素は flex コンテナになれない(Safari)
 * ネストされたflexコンテナで align-items: baseline が効かない(FF)
 * flexアイテムを折り返す場合に、最小・最大サイズの定義が無視される(Safari)
 * インライン要素がflexアイテムとして扱われない(IE11)

このような問題は、flexbugsというリポジトリに集約されています。

https://github.com/philipwalton/flexbugs

一部和訳を作成しました。

https://github.com/hashrock/flexbugs-ja

flexbugsを元に、Qiitaに資料を作成しました。

[flexboxのバグに立ち向かう（flexboxバグまとめ） - Qiita](https://qiita.com/hashrock/items/189db03021b0f565ae27)


# 参考資料

本ガイドは、[Solved by Flexbox](https://philipwalton.github.io/solved-by-flexbox/)を下敷きにしております。和訳版を用意しましたので、ぜひ目を通してみてください。

http://hashrock.github.io/solved-by-flexbox-ja/