Share on

CSSプロパティのflexboxでつくるレイアウトを崩さない作法

CSSプロパティのflexboxでつくるレイアウトを崩さない作法

デザインカンプの見た目通りのWebサイトを作成しても、テキスト量や要素の増加によってレイアウトが崩れることがあります。

「再現度を保ちつつ、レイアウトの崩れない柔軟なサイトを作成することはできないのでしょうか?」

そんなお悩みを今回はCSSプロパティのFlexbox(フレックスボックス)を用いて解決していきます。
Flexboxはレイアウトの設定によく用いられるfloatに比べて、横並び/センター揃え/等間隔配列など、行と列を同時に制御することができる優れもの。

以前まではブラウザによって挙動が違ったりサポートしていなかったりとクロスブラウザによる問題がありましたが、最近ではサポートが進み安定して使用できるようになりました。これから利用頻度が上がっていくだろうFlexboxについて実例を交えてご紹介します。

Flexboxの作法

まず基本の設定からです。

Flexboxの基本設定

Flexboxコンテナー

Flexboxを使うには「Flexboxコンテナー」という親要素の設定が必要です。CSSで「display:flex;」を指定すると定義することができます。

Flexboxアイテム

「Flexboxコンテナー」の子要素のことを「Flexboxアイテム」と呼びます。とくにCSSで指定する必要はありませんが、孫要素までは「Flexboxアイテム」に定義されないので注意が必要です。

ここまでで基本の設定は完了。

親要素に使用できるプロパティ

親要素につかえるプロパティは以下があります。

flex-direction

アイテムの並び順を指定します。

row 子要素が水平方向に横並びに配置されます。
row-reverse 子要素が水平方向に逆順で横並びに配置されます。
column 子要素が垂直方向に縦並びに配置されます。
column-reverse 子要素が垂直方向に逆順で縦並びに配置されます。

flex-wrap

アイテムの折り返しを指定する

wrap 子要素が折り返します。
wrap-reverse 逆順に子要素が折り返します。

justify-content

アイテムの水平方向の位置を指定する

flex-start 左揃えで表示します。
flex-end 右揃えで表示します。
center 中央で表示します。
space-around 均等な間隔を空けて表示します。
space-between 両端いっぱいまで均等に間隔を空けて表示します。
space-evenly 子要素と同じサイズを間に設置して表示します。

align-items、align-content

アイテムの垂直方向の位置を指定する

flex-start 子要素を上揃えで配置します。
flex-end 子要素を下揃えで配置します。
center 子要素を上下中央揃えで配置します。
baseline ベースラインに揃えて配置します。

子要素に使用できるプロパティ

Flexboxは、揃えるだけではなく子要素(アイテム)に対して使用できる便利なプロパティがあるので大変便利です。

order 並び順を指定
flex-grow 伸び率を指定
flex-shrink 縮み率を指定
flex-basis ベースの幅を指定
flex 伸び率、縮み率、ベースの幅を一括指定

並び順を指定するorder

orderは画面幅によって要素の表示順序を変更したいときに、マークアップを変更せずに順番を変更できます。親要素にflex-directionを指定して逆順での表示も可能ですが、さらに細かく指定できます。

orderで並び順を変更する
HTML
<div class="item01">左から3番目に表示されます</div>
<div class="item02">左から1番目に表示されます</div>
<div class="item03">左から4番目に表示されます</div>
<div class="item04">左から2番目に表示されます</div>
CSS
.item01 {order: 3;}
.item02 {order: 1;}
.item03 {order: 4;}
.item04 {order: 2;}

次にWebサイトを作るうえでよく登場する定番UIパーツで使い方を紹介していきます。細かい装飾はデザインによって異なるので、サンプルをもとに変更点を加えてください。

ヘッダー/ナビゲーション

ヘッダー/ナビゲーションサンプル

よく見かけるヘッダーのレイアウトです。
Flexboxコンテナーとアイテムを多く使用して、中央寄せや配置の変更を行っています。

HTML

<header class="header">
  <div class="header__logo">
    <a href="#"><img src="https://coosy.co.jp/assets/img/common/img_site_logo.svg" alt="COOSY"></a>
  </div>
  <nav class="header__menu">
    <ul class="nav">
      <li class="item"><a href="#">ABOUT</a></li>
      <li class="item"><a href="#">SERVICE<br> / WORK</a></li>
      <li class="item"><a href="#">WORK</a></li>
    </ul>
    <div class="btn"><a href="#">CONTACT</a></div>
  </nav>
</header>

CSS

.header{
  display: flex;
  align-items: center;
  justify-content: space-between;
  /*.header に flex を指定し、. header__logo と .header__menu を横並びにする。それらを両端に配置します。*/
}
.header .header__menu {
  display: flex;
  align-items: center; 
  /*.header__menuに flex を指定し、.nav と .btn を横並びにする。それらを垂直方向の中央付近にまとめます。*/
}
.header .nav {
  display: flex;
  border-right: 2px solid #444;
  margin-right: 30px; 
  /* .navに flex を指定し、子要素を横並びにする。*/
}
.header .nav .item {
  border-left: 2px solid #444;
}
.header .nav .item a {
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  height: 100%;
  padding: 0 20px; 
  /* .navに flex を指定し、子要素を横並びにする。各プロパティをcenterにして高さを指定することで中央寄せにしている。*/
}
.header .btn a {
  display: block;
  text-align: center;
  margin: 0 auto;
  padding: 6px 28px;
  color: #fff;
  background: #444;
  box-shadow: 0 3px 5px rgb(0 0 0 / 50%);
  border-radius: 50px;
} 

パンくずリスト

親要素で子要素を横並びにしてgapでマージンを一元管理できるため、非常にスッキリとしたCSSになります。

HTML

<ul class="breadcrumb">
  <li><a href="#">TOP</a></li>
  <li><a href="#">SERVICE</a></li>
  <li><strong>SYSTEM</strong></li>
</ul>

CSS

.breadcrumb {
  overflow-x: auto;
  display: flex;
  gap: 0 10px;
  /* .breadcrumb に flex を指定し、子要素を横並びにする。gapで子要素のマージンを指定する。*/
}
.breadcrumb > li:not(:last-child)::after {
  content: "/";
  padding: 0 2px 0 10px;
} 

カード

カードサンプル

記事一覧や実績紹介で使われるレイアウトです。
Flexboxコンテナーとmargin-top: auto;を使用することで、複数行に耐えうる上下間のレイアウトの制御が可能です。

HTML

<ul class="listCard">
  <li class="listCard__item">
    <a href="#">
      <p class="title">タイトル</p>
      <p class="text">1行想定です。</p>
      <div class="btn"><span>MORE</span></div>
    </a>
  </li>
  <li class="listCard__item">
    <a href="#">
      <p class="title">タイトル</p>
      <p class="text">複数行想定のテキストです。複数行想定のテキストです。</p>
      <div class="btn"><span>MORE</span></div>
    </a>
  </li>
  <li class="listCard__item">
    <a href="#">
      <p class="title">タイトル</p>
      <div class="btn"><span>MORE</span></div>
    </a>
  </li>
  <li class="listCard__item">
    <a href="#">
      <p class="title">タイトル</p>
      <p class="text">テキスト</p>
      <div class="btn"><span>MORE</span></div>
    </a>
  </li>
  <li class="listCard__item">
    <a href="#">
      <p class="title">タイトル</p>
      <p class="text">テキスト</p>
      <div class="btn"><span>MORE</span></div>
    </a>
  </li>
</ul>

CSS

.listCard {
  display: flex;
  flex-wrap: wrap;
  gap: 20px 20px;
  /* .listCard に flex を指定し、子要素を横並びにする。wrapで折り返しできるようにする。gapで子要素間にマージンを設ける。*/
}
.listCard .listCard__item {
  width: calc(100% / 3 - 20px);
  background: #fff;
  /* width: calc(最大横幅 / 一行に残したい個数 - gapで横に指定した数値);*/
}
.listCard .listCard__item a {
  display: flex;
  flex-direction: column;
  height: 100%;
  padding: 10px 20px 20px;
  /* .listCard__item に flex を指定し子要素を横並びにしますが、column を指定して子要素に横幅を持たせ改行されないようにします。*/
}
.listCard .btn {
  display: block;
  text-align: center;
  margin: auto auto 0;
  padding: 6px 28px;
  color: #fff;
  background: #444;
  box-shadow: 0 3px 5px rgb(0 0 0 / 50%);
  border-radius: 50px;
  /* margin-topに auto を指定することで下揃えになります。*/
}

タブメニュー

タブ1の内容が表示されます。

タブ2の内容が表示されます。

タブ3の内容が表示されます。

タブ部分をFlexboxで形成しています。
デザインによって文字位置を変更することができます。

HTML

<div class="tabContent">
  <input id="TAB01" type="radio" name="tab" checked="checked">
  <label class="tabContent__label" for="TAB01">タブ1</label>
  <div class="tabContent__main">
    <p>タブ1の内容が表示されます。</p>
  </div>
  <input id="TAB02" type="radio" name="tab">
  <label class="tabContent__label" for="TAB02">タブ2</label>
  <div class="tabContent__main">
    <p>タブ2の内容が表示されます。</p>
  </div>
  <input id="TAB03" type="radio" name="tab">
  <label class="tabContent__label" for="TAB03">タブ3</label>
  <div class="tabContent__main">
    <p>タブ3の内容が表示されます。</p>
  </div>
</div>

CSS

.tabContent{
  display: flex;
  flex-wrap: wrap;
}
.tabContent::after{
  content: "";
  display: block;
  width: 100%;
  height: 0;
  order: -1;
  background: #E2BD20;
}
.tabContent .tabContent__label{
  margin-right: 3px;
  padding: 3px 12px;
  flex: 1;
  order: -1;
  border-radius: 3px 3px 0 0;
  color: #fff;
  background: #444;
  cursor: pointer;
}
.tabContent .tabContent__label:nth-last-of-type(1){ margin-right: 0; }
.tabContent input {
  display: none;
}
.tabContent .tabContent__main{
  width: 100%;
  height: 0;
  overflow: hidden;
  opacity: 0;
}
.tabContent input:checked + .tabContent__label{
  color: #fff;
  background: #E2BD20;
}
.tabContent input:checked + .tabContent__label + .tabContent__main{
  overflow: auto;
  padding: 15px;
  height: auto;
  border: 2px solid #E2BD20;
  transition: .5s opacity;
  opacity: 1;
}

ページネーション

  1. 前へ
  2. 1
  3. 2
  4. 3
  5. 9
  6. 10
  7. 次へ
ページネーションサンプル

ニュース一覧ページに使われる要素です。
横並びのリストをセンター寄せにして、子要素を上下中央配置にしています。

HTML

<ol class="pagenation">
  <li><a href="">前へ</a></li>
  <li><span>1</span></li>
  <li><a href="">2</a></li>
  <li><a href="">3</a></li>
  <li><span class="extend">…</span></li>
  <li><a href="">9</a></li>
  <li><a href="">10</a></li>
  <li><a href="">次へ</a></li>
</ol>

CSS

.pagenation {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
}
.pagenation li:not(:last-child) {
  margin-right: 10px;
}
.pagenation li a,
.pagenation li span {
  display: block;
  padding: 12px;
  line-height: 1;
  background-color: #fff;
  border: 1px solid #444;
}
.pagenation li span {
  color: #fff;
  background-color: #444;
}
.pagenation li span.extend {
    width: auto;
    background: none;
  border: none;
  color: #444;
}

フォーム

お名前必須
メールアドレス必須
お問い合わせ内容必須
フォームサンプル

定番のフォームもFlexboxで作成することができます。
デザインによってタイトルの位置が異なる場合があるので注意しましょう。

HTML

<form>
  <dl class="contactForm">
    <dt class="contactForm__title">
      お名前<span class="required">必須</span>
    </dt>
    <dd class="contactForm__item">
      <input type="text" name="name">
    </dd>
    <dt class="contactForm__title">
      メールアドレス<span class="required">必須</span>
    </dt>
    <dd class="contactForm__item">
      <input type="text" name="email">
    </dd>
    <dt class="contactForm__title">
      お問い合わせ内容<span class="required">必須</span>
    </dt>
    <dd class="contactForm__item">
      <textarea type="textarea" name="contact"></textarea>
    </dd>
  </dl>
</form>

CSS

.contactForm {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
}
.contactForm__title {
  margin: 14px 0;
  padding: 7px 0 0;
  display: flex;
  align-items: center;
  align-self: flex-start;
  justify-content: space-between;
  width: 250px;
}
.contactForm__item {
  margin: 14px 0;
  width: calc(100% - 250px);
}
.required {
  padding: 10px;
  color: #fff;
  line-height: 1;
  background-color: #444;
  margin: 0 14px;
  font-size: 11px;
}
input[type="text"],
textarea {
  display: block;
  padding: 14px;
  width: 100%;
}
textarea {
  height: 200px;
}

テーブルレイアウト

社 名
株式会社クーシー
本 社
テキスト
支 社
テキスト
設 立
1999年11月9日
資本金
2000万円
テーブルレイアウトサンプル

概要ページに用いられるデザインです。
タイトル部分が固定サイズになっているため、コンテンツ部分でその分の幅を減らす必要があります。

HTML

<dl class="tableBasic">
  <dt class="tableBasic__title">社 名</dt>
  <dd class="tableBasic__main">株式会社クーシー</dd>
  <dt class="tableBasic__title">本 社</dt>
  <dd class="tableBasic__main">テキスト</dd>
  <dt class="tableBasic__title">支 社</dt>
  <dd class="tableBasic__main">テキスト</dd>
  <dt class="tableBasic__title">設 立</dt>
  <dd class="tableBasic__main">1999年11月9日</dd>
  <dt class="tableBasic__title">資本金</dt>
  <dd class="tableBasic__main">2000万円</dd>
</dl>

CSS

.tableBasic {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
}
.tableBasic__title {
  margin: 0;
  padding: 20px 30px;
  width: 200px;
  border-bottom: 2px solid #0277b4;
}
.tableBasic__main {
  margin: 0;
  padding: 20px 30px;
  width: calc(100% - 200px);
  border-bottom: 1px solid #6f6f6f;
}

Flexboxの使用が適さないと思うレイアウト

Flexboxの使用が適さないと思うレイアウト

レイアウトの作成や見せ方の変更になにかと便利なFlexboxですが、適していない使われ方もあります。適していないレイアウト例は以下。

  • 連続性・規則性のない構成
  • 絶対配置を多用するデザイン
  • 子要素が存在しない要素

おわりに

今回はどのサイトでも使われている定番UIパーツにFlexboxを使用して制作してみました。
普段使いしているUIパーツをピックアップしたので、実務にすぐに活かせるものがあると思います。改めて記事にまとめていると、もっと調整の余地があると感じた点も多く、わかりやすい記述方法で実装を進めていけたらと思いました。

現在使われている実装方法は、デザインやレイアウトの変更によって使えなくなることもあります。レスポンシブ対応もこなしていかなければならなくなると、もっと煩雑化していくと思います。適材適所でFlexboxを用いてレイアウトの崩れにくい実装を進めていきましょう。

クーシーブログ編集部

この記事を書いた人

クーシーブログ編集部

1999年に設立したweb制作会社。「ラスクル」「SUUMO」「スタディサプリ」など様々なサービスの立ち上げを支援。10,000ページ以上の大規模サイトの制作・運用や、年間約600件以上のプロジェクトに従事。クーシーブログ編集部では、数々のプロジェクトを成功に導いたメンバーが、Web制作・Webサービスに関するノウハウやハウツーを発信中。

お問い合わせはこちらから

Web制作デザイン、丸ごとお任せ

お問い合わせする

Share on

お問い合わせはこちら

CATEGORY LIST