スクリーンショット 2015-11-06 0.22.23.png

Bootstrapは便利ですし、デフォルトのスタイルもフラットでかっこいいですね。

しかし、 Bootstrapがないとレイアウトが組めないプログラマになっていませんか?

私は完全になってます。

というわけで、この記事はフルスクラッチで行けるところまで行ってみよう、というテーマで書き始めました。
レイアウト周りの実装はほとんどSolved by Flexboxが元ネタです。
執筆に先立ち、勉強のためにSolved by Flexbox和訳版を作成しました。詳細が気になる方は、こちらもご参照ください。

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

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

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

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

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

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

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

Bootstrapを取り除く前に

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

参考:NightmareでE2Eテストしつつスクリーンショットとってgifに結合したら目視チェックが最高に楽になった

初期化方針

Sanitize.cssなど、お好みのCSSリセットを適用してください。

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

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

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

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

グリッドシステム

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

スクリーンショット 2015-11-06 0.06.17.png

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

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

スクリーンショット 2015-11-06 0.10.01.png

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

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

flexboxで3分割(レスポンシブ対応)

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

スクリーンショット 2015-11-06 2.27.09.png

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

<div class="feature-list">
  <div class="feature-item"></div>
  <div class="feature-item"></div>
  <div class="feature-item"></div>
</div>
.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

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

スクリーンショット 2015-11-06 2.52.42.png

実装詳細はデモのソースを参照してください。

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

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

また、スマホでPCサイトが表示されないよう、初期倍率を指定する必要があります。head内に下記の記述を追加します(よく見るmaximum-scale等は指定しない)。

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

表示例(800px以下の時):

スクリーンショット 2015-11-06 2.40.00.png

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

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

なお余談ですが、Bootstrapにはデバイスの種類が4種類定義されています。

  • .col-xs-(スマホ向け)
  • .col-sm-(タブレット向け)
  • .col-md-(デスクトップ向け)
  • .col-lg-(大画面デスクトップ向け)

しかし、正直言って、ここまでの細分化は必要無い気がします。
実際、レスポンシブレイアウトを作る際は、スマホ用レイアウトとPC用のレイアウトの2種類のみ作ることが多いです。

追記(2016/02/15):

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

【IE11バグ】 flex-basisにbox-sizingが効かない不具合 – 広告のフジプロ

flexboxで2ペインまたは3ペインレイアウト

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

2カラム
3カラム

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

floatより辛くない「flexbox」でざっくりレイアウト - Qiita

2017-12-11追記:

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

floatより辛くない「flexbox」でざっくりレイアウト

フォーム

下記のようなタイプのフォームは、flexboxで実装することが可能です。詳しくはSolved by flexbox当該記事を参照してください。

スクリーンショット 2015-11-06 2.59.00.png

ボタン

スクリーンショット 2015-11-06 1.19.14.png

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

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

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

スクリーンショット 2015-11-06 3.10.55.png

.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 が同梱されており便利ですが、
ロゴのフォントを選ぶのと同様に、アイコンのスタイルにもいろいろあるので、サイトのテイストと合わせて選ぶのがいいかと思います。

フォーマットについて

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

Typicons

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

http://typicons.com/

スクリーンショット 2015-11-06 3.29.20.png

Genericons

シュッとしています。

http://genericons.com/

スクリーンショット 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

Fontello

http://fontello.com/

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

Bytesize

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

スクリーンショット 2017-12-11 11.18.08.png

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

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

<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
スクリーンショット 2016-02-15 13.17.19.png
スクリーンショット 2016-02-15 13.17.36.png

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

追記: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

参考資料

本ガイドは、Solved by Flexboxを下敷きにしております。和訳版を用意しましたので、ぜひ目を通してみてください。

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