このページの本文へ

Flexboxでサクッと作る!いまどきのメガメニューのマークアップ

2017年08月08日 16時29分更新

文● Kalpesh Singh

  • この記事をはてなブックマークに追加
本文印刷
Webサイトを効率よくレイアウトできるFlexbox。メガメニューの実装を例に、具体的な活用方法を紹介します。

ご存じの方もいるとおり、Flexboxはブラウザーサポートが増えて、はずみがついています。Flexboxなら、使いたくないCSSやJavaScriptハックを扱わずに、複雑なユーザーインターフェイスを作れます。

Flexboxはリニアレイアウトモデルを採用しており、スペースの計算をせずにコンテンツを上下左右にレイアウトできます。Flexレイアウトはコンテナ内の要素にレスポンシブに反応するので、メディアクエリの使用を減らせます。

この記事では、リニアレイアウトモデルを使い、メガナビゲーションメニューを作ります。メニューを作る中で、Flexboxでユーザーインターフェイスコンポーネントを簡単に作成し、拡張できることを体験してください。

Flexboxの特徴を詳しく解説するのではなく、実用的な使い方に焦点をあてます。Flexboxの基礎的な入門については、次のリソースを参考にしてください。

作成するメニュー

作成するメニューをCodePenをフルスクリーンにして確認してください。

チュートリアルは、3つのパートに分かれます。

  1. ナビゲーションバーを作る:Flexboxを使って、仮想のECプラットホーム用に簡単なナビゲーションバーを作る
  2. ドロップダウンセクションを1つ作る
  3. 1つのドロップダウンセクションを3列に制限する

ナビゲーションバーを作る

ナビゲーションバーのマークアップは簡単です。2つのクラス(navbarとmenu)でデモを作成します。チュートリアルに無関係なスタイルは、CSSから削除します。

<nav class="navbar">
  <ul class="menu">
    <li>
      <a href="#">
        Electronics
        <!-- FontAwesome icon -->
        <i class="fa fa-angle-down"></i>
      </a> 
    </li>

    <!-- ... More nav items here... -->

  <ul>
</nav>

スペース内でナビゲーションバーをセンタリングするにはnavbarクラスを使います。flexboxを使うmenuクラスに焦点を絞ります。

ナビゲーション項目を水平に並べます。各項目は等間隔に並べ、スペースが十分でない場合には、必要に応じて縮小させます。

.menu要素にflexフォーマットコンテキストを確立します。display: flexを指定すると.menu要素(flexコンテナ)の直接の子はすべて、flexアイテムとなります。

メニュー項目の幅を揃えます。flex: 1を加えると、幅を揃えたまま、拡大できます。

.navbar .menu {
  display: flex;
  position: relative;
}

.navbar .menu li {
  flex: 1;
  display: flex;
  text-align: center;
}

.navbar .menu a {
  flex: 1;
  justify-content: center;
  color: #ffffff;
  padding: 20px;
}

コードを見て、display: flexをすべてのflexアイテム(.navbar .menu li)で繰り返すのか、不思議に感じたかもしれません。

デモでは、メニュー項目をホバーすると、背景の色が変わります。flexアイテムのdisplayプロパティをflexに設定しないと、li要素のみ等幅になり、中身には影響しません。ハイライトされるのに、クリックできないところができてしまうのです。

コンテンツを親と同じ幅まで広げるには、flexアイテムもflexコンテナに入れます。ネストされたa要素は(flex: 1を用いて)親と同じ幅まで広げます。これでハイライトされた領域はどこでもクリック可能になります。

li要素をflexコンテナにしなくても同じことができますが、追加で3つのプロパティ(display: inline-block,width: 100%, box-sizing: border-box)が必要なのでやめました。

ここまでのデモです。

5つのFlexboxプロパティで、ナビゲーションバーができました。簡潔な方法だと納得いただけたでしょうか。

次は、メガナビゲーションのセクションを1つ作る方法を紹介します。

ドロップダウンセクションを1つ作る

ドロップダウンセクション作成に必要なマークアップを示します。以下をベースに、複数のセクションに拡張します。container__listアイテムをコピーして追加のセクションを作ります。

<ul class="container">
  <!-- single column -->
  <div class="container__list">
    <!-- menu item -->
    <div class="container__listItem">
      <div>Televisions</div>
    </div>

    <!-- ... other menu items here -->

  </div>
</ul>

containerはflexコンテナで、直接の子(container__list)はflexアイテムです。container__listは複数のナビゲーション項目を持ち、container__listItemでラップされます。今回はdivの中にコンテンツをラップしました。

CSS
.container {
  /* initially hidden; display:flex on hover */
  display: none;
  position: absolute;
  top: 56px;
  left: 0;
  right: 0;
  background-color: #ffffff;
  padding: 20px;
  text-align: left;
}

.container__list {
  flex: 1;
  display: flex;
  flex-wrap: wrap;
}

.container__listItem {
  flex: 0 0 25%;
  padding: 10px 30px;
}

.container__listItem > div {
  color: #DB6356;
}

container__listflex-wrapプロパティを使っても、ナビゲーションバーには使われません。スペースが足りないと、ナビゲーションバーの項目が次の行までラップしませんが、横方向の使用可能なスペースが減った場合、揃って縮みます。


container__list
アイテムは逆です。リスト項目にスペースを25%使いたいので、1行当たり最大4個の項目が入ります。flex-wrap: wrapで実現します。

flex-growを0にしたのは、項目の数が4未満のとき等間隔で並ぶのを防ぐためです。項目がスペースの25%を占めるよう強制できます。

divでラップされたコンテンツがはみ出さないためには、コンテンツが直接flexの子(container__listItem)にあればよく、クリップされたテキストを省略記号(“…”)で置換すれば大丈夫です。

.example {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

コンテンツをdivに入れましたが、container__listItemでラップされているため、上の解決法は使えません。Flexboxと短縮したテキストに解決法が示されています。下のコードでは、各宣言ブロックの「updated」コメントの下の行が問題に対処する部分です。

.container__list {
  flex: 1;
  display: flex;
  flex-wrap: wrap;
  /* updated */
  min-width: 0;
}

.container__listItem {
  flex: 0 0 25%;
  padding: 10px 30px;
  /* updated */
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.container__listItem > div {
  color: #DB6356;
  /* updated */
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

ドロップダウンセクションを3列に制限する

作業の大部分は終わっています。ここでは項目を3列に制限したドロップダウンセクションを加えます。

container__listを2回コピーして、新しいドロップダウンセクション「Appliances」で使います。デモが目的なので実際は、JavaScriptやほかのバックエンド言語で作ったリストを使います。

ユーザーインターフェイスを少し修正するため、クラス「has-multi」を追加し、プロパティを何個かオバーライドします。

.container.has-multi .container__list {
  flex-basis: 33.333%;
}

.container.has-multi .container__list:not(:last-child) {
  border-right: solid 1px #f3f3f3;
  margin-right: 20px;
}

.container.has-multi .container__listItem {
  flex-basis: 100%;
}

コンテナに3つのセクションを表示するため、flex-basisを33.333%に設定しました。flex-basisだけ変更し、残りのプロパティflex-growflex-shrinkは、セクションが1つのコードから継承しています。

container__listの数が3より小さければ柔軟性があります。リストの数が2つなら、container__list項目が大きくなり、スペースを分配します。各項目が全体の幅の50%を占めます。

.container__listItemflex-basis: 100%に設定することで、container__listが1列になります。50%にすれば、各セクションが2列になります。

メガメニューの使い勝手における注意点

メガメニューを例に解説しました。使い勝手を向上するために、長所と短所について書かれているリソースを紹介します。

メガメニューナビゲーションはオプションをすべて表示するため、eコマースのWebサイトで効率的に利用できます。私はIntelのナビゲーションが気に入っています。

最後に

このチュートリアルで作ったメガメニューはレスポンシブではありません。メインのメニューバーが小さなスクリーンに現れますが、メガメニューは使えず、最上層のリンクだけが機能します。このチュートリアルには十分だと考えました。デモに手を加えて、自由に改造してください。

Flexboxはコンテンツをセンタリングするためだけの道具ではありません。メガドロップダウンメニューナビゲーションシステムは、Flexboxの能力と簡便さを示すのにはいい題材です。そのよさがうまく伝えられたら幸いです。

(原文:Building Mega Menus with Flexbox

[翻訳:関 宏也/編集:Livit

Web Professionalトップへ

WebProfessional 新着記事