これが知りたかった!よく使うUI要素をFlexboxを使ってシンプルに簡単に実装するチュートリアル
Post on:2016年3月2日
Flexboxの基本的な使い方から、ヘッダ・フッタ・ナビゲーション・タブ・カードなど、Webページでよく使うUIコンポーネントをFelxboxで実装するチュートリアルを紹介します。
2016年1月12日にIEの古いバージョンのサポートが終了し、Flexboxをそろそろ使うか、と考えている人も多いと思います。
Flexbox Patterns
Flexbox Patterns -GitHub
Flexboxの実装に役立つ各プロパティの説明は、下記が分かりやすいです。
以下、各ポイントを意訳したものです。
※当ブログでの翻訳記事は、元サイト様に許可を得て翻訳しています。
- 「display: flex;」からはじめよう
- 01. 要素を水平に配置する
- 02. Flexboxで実装する「タブ」
- 03. Flexboxで実装する「ヘッダ」
- 04. Flexboxで実装する「フォームのフッタ」
- 05. Flexboxで実装する「サイドバー」
- 06. Flexboxで実装する「天地左右の中央に配置」
- 07. Flexboxで実装する「アイコンを中央に配置」
- 08. Flexboxで実装する「フィーチャーリスト」
- 09. Flexboxで実装する「カード」
- 10. Flexboxで実装する「カードの複数配置」
「display: flex;」からはじめよう
Flexboxの出発点は「display: flex;」プロパティです。
要素にこのプロパティを加えることで、あなたはFlexboxを使えるようになります。
1 |
display: flex; |
「display: flex;」のプロパティが何をしていると思いますか?
このプロパティは、Flexコンテナの主軸(デフォルトで水平軸)に沿ってアイテム(子要素)を配置することを明示しています。
対応ブラウザは、下記の通り。
Flexboxの各ブラウザのサポート状況 -Can I use
「display: flex;」がどのように機能するか、UIコンポーネントを作るためにどのように使うか、見てみましょう。
01. 要素を水平に配置する
まずは、シンプルな「ステッパー インプット」です。
これはJavaScriptを使用すると、「-」で値を減少させ、「+」で値を増加させます。
通常これを実装する時は、ボタンをインライン化させ、入力フィールドに「display: inline-block;」を加え、「float: left;」で配置するでしょう。しかし、この表示結果を実現するにはそれらの要素両方ともに特定のセレクタが必要となります。
Flexboxを使用すると、そのセレクタは必要ありません。
コンテナに「display: flex;」を加えるだけで、同じ効果を達成することができます。あとは、Flexboxの仕様通りに、アイテムが水平軸に沿って並べられます。
これはFlexboxの基本で、コンテナの中にアイテムを左から右に主軸に沿って配置します。
HTML
コンテナは「.stepperInput」で、アイテムはbuttonが2つとinputが1つです。
1 2 3 4 5 |
<div class="stepperInput"> <button class="button button--addOnLeft">-</button> <input type="text" placeholder="Age" value="32" class="input stepperInput__input"/> <button class="button button--addOnRight">+</button> </div> |
SCSS
コンテナに「display: flex;」を指定します。
あとは、ただの装飾です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
.stepperInput { display: flex; } .stepperInput__input { border-left: 0; border-right: 0; width: 60px; text-align: center; } .button { cursor: pointer; padding: 5px 15px; color: #FFFFFF; background-color: #4EBBE4; font-size: 12px; border: 1px solid #16A2D7; border-radius: 4px; } .button--addOnLeft { border-top-right-radius: 0; border-bottom-right-radius: 0; } .button--addOnRight { border-top-left-radius: 0; border-bottom-left-radius: 0; } .input { border: 1px solid #D7DBDD; padding: 0 10px; border-radius: 0; box-shadow: none; } |
02. Flexboxで実装する「タブ」
「display: flex;」はかなり用途が広いプロパティです。
タブも上記と同じ方法で実装できます。
HTML
コンテナは「.tabs」です。
1 2 3 4 5 6 |
<div class="tabs"> <div class="tab is-tab-selected">Tab 1</div> <div class="tab">Tab 2</div> <div class="tab">Tab 3</div> <div class="tab">Tab 4</div> </div> |
SCSS
コンテナに「display: flex;」を指定することで、アイテムである各タブを左から右に主軸(水平軸)に沿って配置します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
.tabs { display: flex; border-bottom: 1px solid #D7DBDD; } .tab { cursor: pointer; padding: 5px 30px; color: #16A2D7; font-size: 12px; border-bottom: 2px solid transparent; &.is-tab-selected { border-bottom-color: #4EBBE4; } } |
03. Flexboxで実装する「ヘッダ」
左から右に沿って配置するだけでなく、今度は切り離して配置してみましょう。
ここにあるヘッダのアイテムは、ロゴ、ナビゲーション、Settingボタンの3つで構成されています。
通常これを実装する時は、ロゴとナビゲーションの2つをラッパーで包み、フロートを使い、そのラッパーを左に、ボタンを右に配置するでしょう。もちろん、clearfixも必要です。
Flexboxを使うと簡単に、そしてシンプルに実装できます。
Flexboxを使う時にもラッパーは必要とします。Flexboxは配置する時に親要素(コンテナ)が必要だからです。しかしこのコンテナに特別なclassは必要なく、clearfixも必要ありません。
HTML
ロゴとナビゲーションの2つ、ボタンの1つを包むコンテナを用意します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<div class="siteHeader"> <!-- This section gets pushed to the left side--> <div class="siteHeader__section"> <div class="siteHeader__item siteHeaderLogo"> <div class="fa fa-inbox"></div> </div> <div class="siteHeader__item siteHeaderButton is-site-header-item-selected">Inbox</div> <div class="siteHeader__item siteHeaderButton">Sent</div> <div class="siteHeader__item siteHeaderButton">Trash</div> </div> <!-- This section gets pushed to the right side--> <div class="siteHeader__section"> <div class="siteHeader__item siteHeaderButton">Settings</div> </div> </div> |
SCSS
ヘッダ全体のコンテナ「.siteHeader」、子要素のグルーピング用のコンテナ「.siteHeader__section」に、「display: flex;」を指定します。
そして、2つの新しいプロパティを使います。
ヘッダ全体のコンテナに「justify-content: space-between;」を指定し、最初と最後のアイテムを両端に、残りは等間隔で配置します(この例では残りのアイテムはありません)。
グルーピング用のコンテナに「align-items: center;」を指定し、コンテナのクロス軸の中央に配置します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
.siteHeader { display: flex; justify-content: space-between; padding: 10px; background-color: #56727C; } .siteHeader__section { display: flex; align-items: center; } .siteHeader__item { padding: 5px 15px; font-size: 12px; & + & { margin-left: 5px; } &.is-site-header-item-selected { color: #FFFFFF; background-color: #415F69; border-radius: 4px; } } .siteHeaderLogo { font-size: 20px; line-height: 0; color: white; } .siteHeaderButton { cursor: pointer; color: #D9E9EF; } |
04. Flexboxで実装する「フォームのフッタ」
フォームのフッタに、進捗状況のスピナーを必要とするかもしれません。
これは異なる情報構造のものが並ぶ状態で、フォームのボタンとスピナーはマークアップの構造上、分けて配置されています。
HTML
アイテムはスピナーとフォームのボタン2つ、それぞれのコンテナを用意します。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<div class="formFooter"> <!-- This section gets pushed to the left side--> <div class="formFooter__section"> <div class="formFooter__item formFooterFeedback"> <div class="fa fa-spinner formFooterSpinner"></div> Saving... </div> </div> <!-- This section gets pushed to the right side--> <div class="formFooter__section"> <div class="formFooter__item button button--clear">Reset</div> <div class="formFooter__item button">Save</div> </div> </div> |
SCSS
全体のコンテナには、最初と最後のアイテムを両端に、クロス軸の中央に配置します。
スピナー、フォームのボタンはクロス軸の中央に配置します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
.formFooter { display: flex; align-items: center; justify-content: space-between; border-top: 1px solid #D7DBDD; padding: 10px; } .formFooter__section { display: flex; align-items: center; } .formFooter__item { & + & { margin-left: 5px; } } .formFooterFeedback { color: #86969C; font-size: 12px; line-height: 0; } .formFooterSpinner { animation: formFooterSpinner 1s infinite steps(8, end); } @keyframes formFooterSpinner { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } .button--clear { color: #16A2D7; background-color: #FFFFFF; border: 1px solid #FFFFFF; } |
05. Flexboxで実装する「サイドバー」
ここまでは水平軸に沿って配置してきましたが、今度は垂直軸に沿って配置してみましょう。
よく見かけるサイドバーに配置されたナビゲーションを実装します。
一見、div要素を上から並べるだけで実装できるように見えますが、「Legal」が最下部にあるため、div要素を上から並べるだけではできません。
この場合、Flexboxを使うと非常に簡単に実装できます。
まずはコンテナに「display: flex;」を加え、最初と最後のアイテムを両端に配置する「justify-content: space-between;」を使います。そして、水平軸ではなく、垂直軸にするために「flex-direction: column;」を使用します。
HTML
上3つのアイテムと下1つのアイテムにコンテナを用意します。
1 2 3 4 5 6 7 8 9 10 11 12 |
<div class="sideBar"> <!-- This section gets pushed to the top--> <div class="sideBar__section"> <div class="sideBar__item is-side-bar-item-selected">Inbox</div> <div class="sideBar__item">Contacts</div> <div class="sideBar__item">Account</div> </div> <!-- This section gets pushed to the bottom--> <div class="sideBar__section"> <div class="sideBar__item">Legal</div> </div> </div> |
SCSS
「flex-direction: column;」を使用すると、アイテムは上から下に垂直方向に配置されます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
.sideBar { display: flex; flex-direction: column; justify-content: space-between; height: 300px; width: 150px; border-right: 1px solid #D7DBDD; background-color: #FCFDFD; padding: 10px; } .sideBar__item { cursor: pointer; padding: 5px 10px; color: #16A2D7; font-size: 12px; &.is-side-bar-item-selected { background-color: #EEF3F5; border-radius: 4px; } } |
06. Flexboxで実装する「天地左右の中央に配置」
水平軸と垂直軸が使えるようになったので、今度は天地左右の中央に配置してみましょう。
Flexbox無しで実装するには、絶対配置や2Dの変形で相殺するなど、若干のCSSハックを伴います。Flexboxで実装すると、コンテナに4つのプロパティを使うだけです。
HTML
コンテナ「.centeredPrompt」を天地左右の中央に配置します。
1 2 3 4 5 6 7 8 |
<div class="centeredPrompt"> <div class="centeredPrompt__item centeredPromptIcon"> <div class="icon fa fa-smile-o"></div> </div> <div class="centeredPrompt__item centeredPromptLabel">Welcome to the app!</div> <div class="centeredPrompt__item centeredPromptDetails">Thanks for signing up. Let’s take a look around.</div> <div class="centeredPrompt__item button">Begin tour</div> </div> |
SCSS
天地左右の中央に配置するコンテナに必要なのは、4つのプロパティだけ。
- 「display: flex;」: コンテナに必ず指定します。
- 「flex-direction: column;」: コンテナの主軸の方向を設定します。
- 「align-items: center;」: アイテムをコンテナのクロス軸の中央に配置します。
- 「justify-content: center;」: アイテムをコンテナの中央に配置します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
.centeredPrompt { display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 300px; padding: 10px; } .centeredPrompt__item { & + & { margin-top: 5px; } } .centeredPromptIcon { font-size: 60px; line-height: 0; } .centeredPromptLabel { color: #86969C; font-size: 30px; font-weight: 700; text-align: center; } .centeredPromptDetails { color: #86969C; font-size: 16px; margin-bottom: 10px; text-align: center; } .icon { color: #BCD2DA; } |
07. Flexboxで実装する「アイコンを中央に配置」
「天地左右の中央に配置」と同様にプロパティを使用して、ある要素の天地左右の中央に配置することもできます。
HTML
div要素のサークルに、アイコンを配置します。
1 2 3 |
<div class="centeredIcon"> <div class="icon fa fa-phone"></div> </div> |
SCSS
コンテナに使用するプロパティは、同じです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
.centeredIcon { display: flex; flex-direction: column; align-items: center; justify-content: center; border: 1px solid #D7DBDD; font-size: 40px; width: 90px; height: 90px; border-radius: 100%; box-shadow: 0 2px 1px rgba(#000000, 0.05), 0 2px 3px rgba(#000000, 0.05), 0 4px 8px rgba(#000000, 0.05); } |
08. Flexboxで実装する「フィーチャーリスト」
フィーチャーリストとは、プロダクトやサービスの特徴を画像やテキストなどで記載したコンポーネントです。
上記のように互い違いに配置されたレイアウトも、Flexboxを使うと簡単に実装できます。
HTML
アイコンとテキストをセットにして、コンテナで内包します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<div class="featureListItem"> <div class="featureListItem__icon"> <div class="icon fa fa-calendar"></div> </div> <div class="featureListItem__description">The calendar feature makes scheduling a snap.</div> </div> <div class="featureListItem featureListItem--reverse"> <div class="featureListItem__icon"> <div class="icon fa fa-dashboard"></div> </div> <div class="featureListItem__description">Our dashboard gives you a bird’s-eye-view-at-a-glance-on-the-go.</div> </div> <div class="featureListItem"> <div class="featureListItem__icon"> <div class="icon fa fa-envelope"></div> </div> <div class="featureListItem__description">You can get notified by email or SMS.</div> </div> |
SCSS
ここでのポイントは「flex-direction: row-reverse;」です。
このプロパティを与えたコンテナは、アイテムを右から左へ(rtl)水平方向に配置します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
.featureListItem { display: flex; align-items: center; max-width: 400px; padding: 10px; & + & { border-top: 1px solid #D7DBDD; } } .featureListItem--reverse { flex-direction: row-reverse; } .featureListItem__icon, .featureListItem__description { padding: 5px 15px; } .featureListItem__icon { font-size: 50px; line-height: 0; } .featureListItem__description { color: #86969C; font-size: 12px; } |
09. Flexboxで実装する「カード」
09と10で、Flexboxを使った少し複雑なレイアウトに挑戦してみましょう。
カードを実装するには、ここまでに使ったプロパティで大丈夫です。
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
垂直の主軸に沿ってアイテムを配置し、各アイテムは中央に揃えます。
HTML
アイコンとテキスト、価格の2つでコンテナを分けます。
1 2 3 4 5 6 7 |
<div class="card card--fixedWidth"> <div class="card__description"> <div class="icon fa fa-flask card__descriptionIcon"></div> <div class="card__descriptionText">Science potion</div> </div> <div class="card__price">Costs $5</div> </div> |
SCSS
垂直方向にする「flex-direction: column;」がポイントです。
各子コンテナには、「align-items: center;」と「justify-content: center;」で天地左右の中央に配置します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
.card { display: flex; flex-direction: column; border: 1px solid #CAD0D2; border-radius: 4px; overflow: hidden; } .card__description { display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 15px; } .card__descriptionIcon { font-size: 32px; margin-bottom: 10px; } .card__descriptionText { color: #57727C; font-size: 12px; text-align: center; } .card__price { text-align: center; color: #57727C; font-size: 12px; font-weight: 700; padding: 5px 15px; border-top: 1px solid #D7DBDD; background-color: #EEF3F5; } .card--fixedWidth { max-width: 120px; } |
10. Flexboxで実装する「カードの複数配置」
いよいよ、最後のチュートリアルになりました。
カードを複数配置し、カードグループのコンポーネントを作成します。実装のポイントは、2つです。
- カードの幅は、その内容の量に関わらず同じサイズにします。
- カードの高さも同様に同じサイズにします。
これをFlexbox無しで実装するには、全部のカードを一つのtable要素にするか、全部のカードを絶対位置で配置してサイズを%とpxの両方を算出して適用するかでしょう。
Flexboxを使うとこれは非常に簡単です、ただし新しいプロパティを使用します。ここまではコンテナのプロパティでしたが、アイテムに適用するプロパティです。
HTML
HTMLの構造は、全部のカードを内包するコンテナが加わります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<div class="cardGroup"> <div class="card cardGroup__card"> <div class="card__description cardGroup__cardDescription"> <div class="icon fa fa-thumbs-o-up card__descriptionIcon"></div> <div class="card__descriptionText">Trial</div> </div> <div class="card__price">Free!</div> </div> <div class="card cardGroup__card"> <div class="card__description cardGroup__cardDescription"> <div class="icon fa fa-trophy card__descriptionIcon"></div> <div class="card__descriptionText">Basic tier<br/>(most popular)</div> </div> <div class="card__price">$10.00</div> </div> <div class="card cardGroup__card"> <div class="card__description cardGroup__cardDescription"> <div class="icon fa fa-bolt card__descriptionIcon"></div> <div class="card__descriptionText">Advanced tier<br/>(only for enterprise-level professionals)</div> </div> <div class="card__price">$6,000.00</div> </div> </div> |
SCSS
まずはカードのコンテナ「.cardGroup__card」に、「flex: 1 1 0;」指定します。これはコンテナの中で幅を等しくします。この3つの数字は、下記の3つのプロパティのショートハンドです。
- 「flex-grow: 1;」: フリーのポジティブなスペースがある場合にアイテムが他のアイテムと比較してどのくらいの大きさになるかを指定します。
- 「flex-shrink: 1;」: フリーのネガティブなスペースにコンテナ内のアイテムが残りのアイテムと比較してどのくらい縮まるかを指定します。
- 「flex-basis: 0;」: コンテナ内の残りのスペースが適用される前にアイテムのサイズを決定します。「0」にセットすることで、アイテムのサイズはコンテナのサイズによって決定されます。
この指定で1つ目の条件を満たし、すべてのカードの幅が同じになります。
2つ目の条件の高さを揃えるためには、この指定に少し手を加え、「 flex: 1 1 auto;」と記述します。
- 「flex-basis: auto;」: アイテムの最初のメインとなるサイズを元に、幅と高さのプロパティを同じ値にします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
.cardGroup { display: flex; border: 1px solid #CAD0D2; border-radius: 4px; overflow: hidden; } .cardGroup__card { flex: 1 1 0; border: none; border-radius: 0; & + & { border-left: 1px solid #D7DBDD; } } .cardGroup__cardDescription { flex: 1 1 auto; } |
sponsors