ご存じの方もいるとおり、Flexboxはブラウザーサポートが増えて、はずみがついています。Flexboxなら、使いたくないCSSやJavaScriptハックを扱わずに、複雑なユーザーインターフェイスを作れます。
Flexboxはリニアレイアウトモデルを採用しており、スペースの計算をせずにコンテンツを上下左右にレイアウトできます。Flexレイアウトはコンテナ内の要素にレスポンシブに反応するので、メディアクエリの使用を減らせます。
この記事では、リニアレイアウトモデルを使い、メガナビゲーションメニューを作ります。メニューを作る中で、Flexboxでユーザーインターフェイスコンポーネントを簡単に作成し、拡張できることを体験してください。
Flexboxの特徴を詳しく解説するのではなく、実用的な使い方に焦点をあてます。Flexboxの基礎的な入門については、次のリソースを参考にしてください。
作成するメニュー
作成するメニューをCodePenをフルスクリーンにして確認してください。
チュートリアルは、3つのパートに分かれます。
- ナビゲーションバーを作る:Flexboxを使って、仮想のECプラットホーム用に簡単なナビゲーションバーを作る
- ドロップダウンセクションを1つ作る
- 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の中にコンテンツをラップしました。
container__listでflex-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-growとflex-shrinkは、セクションが1つのコードから継承しています。
container__listの数が3より小さければ柔軟性があります。リストの数が2つなら、container__list項目が大きくなり、スペースを分配します。各項目が全体の幅の50%を占めます。
.container__listItemをflex-basis: 100%に設定することで、container__listが1列になります。50%にすれば、各セクションが2列になります。
メガメニューの使い勝手における注意点
メガメニューを例に解説しました。使い勝手を向上するために、長所と短所について書かれているリソースを紹介します。
メガメニューナビゲーションはオプションをすべて表示するため、eコマースのWebサイトで効率的に利用できます。私はIntelのナビゲーションが気に入っています。
最後に
このチュートリアルで作ったメガメニューはレスポンシブではありません。メインのメニューバーが小さなスクリーンに現れますが、メガメニューは使えず、最上層のリンクだけが機能します。このチュートリアルには十分だと考えました。デモに手を加えて、自由に改造してください。
Flexboxはコンテンツをセンタリングするためだけの道具ではありません。メガドロップダウンメニューナビゲーションシステムは、Flexboxの能力と簡便さを示すのにはいい題材です。そのよさがうまく伝えられたら幸いです。
(原文:Building Mega Menus with Flexbox)
[翻訳:関 宏也/編集:Livit]