背景

先月からビジュアル情報処理研究合宿のHPを作っていたのですが(完成版ページ)、最初にページデザインをお願いした後輩から上がってきたデザイン案では「ナビゲーションバーを幅いっぱいにして各項目を等幅で実装し、スマホ版では縦並びにする」ような形になっていました。

私のようなホリデーWebエンジニア(口悪く言えば「にわか」)は「とりあえずBootstrapあたりのコンポーネントライブラリを使ってサクッと出来るっしょ~www」的な希望的観測で実装していたのですが、いざNavbarを作って確認してみると…あれ?動かないぞ、と。

    <nav class="navbar navbar-default navbar-static-top">
      <!-- Difinition for Mobile device view -->
      <div class="navbar-header">
       <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#my-navbar">
        <span class="sr-only">Toggle Navigation</span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
       </button>
       <a href="#" class="navbar-brand">メニュー</a>
      </div>

      <div class="collapse navbar-collapse" id="my-navbar">
       <ul class="nav navbar-nav nav-justified" id="NavbarContent">
       <!-- この部分は動的生成しているので省略 -->
       </ul>
      </div>
    </nav>

これのキモは、ナビゲーションバーの各li項目をulの幅いっぱいにして各項目の幅が同じになるようにulのクラス要素にnav-justified指定をする点。これを入れることで、デザイン案のようなナビゲーションバーができる、はずだった。

動きを見ると……なんだこのゴミ。等幅どころか画像載せる気力なくすぐらい崩れてやがる。

とりあえず、Bootstrapのガイドラインを見てみる。

**Justified navbar nav links are currently not supported.**

ファーwwwwwwwww

さーて、どうしてくれようか。

よく読むと、同じナビゲーションバーでもtabsとかpillsにすればjustifiedにはできるらしいことが分かり、とりあえず指定してみたけど、今度は配色をカスタムしたことが災いしてリンクテキストが読めない。これは弱った。どうしよう。

と思いながらとりあえずググッてみると、やっぱりハマってる人は多かったらしく、StackOverflowがすぐに引っかかった。ひとまず、floatを解除してやればいいみたいなので、自己定義CSSファイルに以下のような指定を追加。

    .nav-justified {
      position: relative;
    }

    .nav-justified > li {
      float: none;
    }

    .nav-justified > li > a {
      vertical-align: middle;
      display: block;
      width: 100%;
      height: 100%;
    }

とりあえずこれで等幅メニューにはなった。

諸々の修正&dividerもどきの付加

でもこの状態でNavbar-Brandは邪魔だし、デザインで指定されている区切り(divider)が無い。それに、画面サイズが中途半端な時に2行に渡るようなli要素があるとactive指定したリンクが浮いたり、スマホ版メニューでも何故か左に寄っていたり。

2行になる時の対策がどうあがいても上手く行かなかったので、とりあえず「992px(col-md)」をメニュー切り替えのタイミングにすることと、モバイル版とデスクトップ版でボーダー指定を切り替えることで対応することに。さらに追記したCSSが以下の様な感じ。

    @media screen and (min-width: 992px) {
      .navbar-brand {
        display: none;
      }

      .navbar-nav > li {
        border-right: 1px solid #FFFFFF;
        height: 100%;
      }

      .navbar-nav > li > a {
        font-size: 14px;
      }

      .navbar-nav {
        border-left: 1px solid rgb(147, 203, 66);
      }
    }

    @media screen and (max-width: 992px) {
      .navbar-brand {
        display: block;
      }

      .navbar-nav {
        display: table;
        float: none!important;
        margin: 0px;
      }

      .navbar-nav > li {
        display: table-row;
        float: none;
        border: 2px;
      }

      .navbar-nav > li > a {
        display: table-cell;
        left: 0;
        right: 0;
        width: 100%;
        height: 100%;
      }
    }

    /* IE対策 */
    @media screen and (min-width: 1200px) {
      .navbar-nav > li > a {
        font-size: 16px;
      }
    }

最後のIE対策は、Chromeなどでは問題なかったんだけど1200pxら辺でテキストが2行になる問題がまた発生したので、とりあえずこの時はナビゲーションバーを折りたたまずにリンクテキストのフォントサイズを少し下げることで対応する形にしました。

その他は、デスクトップ版とモバイル版でNavbar-Brandの表示を切り替えたり、ボーダーの向きを変更するような指定を追加しています。モバイル版ではliをテーブル扱いにすることで、左に寄ったり項目が浮くような問題をクリアしています(ぶっちゃけ、汚いやり方な気がしますが)。

最後にvariables.lessでナビゲーションバーが折りたたまれるタイミングをscreen-md-minに変更し、完了です。

    //** Number of columns in the grid.
    @grid-columns: 12;

    //** Padding between columns. Gets divided in half for the left and right.
    @grid-gutter-width: 30px;

    //** Point at which the navbar becomes uncollapsed.
    @grid-float-breakpoint: @screen-md-min;

実際にご覧ください(トリビアの紹介風に)

そして出来たNavbarがこちら。 フルサイズ版

とりあえず、Bootstrap3でもJustifiedで、かつちゃんとボーダーが付いてレスポンシブなナビゲーションバーが作れましたとさ。めでたしめでたし。