[CSS3] flexboxによるレスポンシブサイトの作り方 – 2カラム編(サンプル付き)

 2017.06.01  2017.10.13

前回は「[CSS3] flexboxの仕様と画像付きプロパティ一覧」という記事で、flexboxの基本的な仕様とプロパティについて説明しました。

今回はこのflexboxを使って以下のようなレスポンシブなサイトを作ってみたいと思います。flexboxによるシングルページの作成方法はこちらの記事で紹介していますので、あわせてどうぞ!

▼デスクトップでの表示flexboxレスポンシブレイアウト

基本的なレイアウト

ヘッダー、フッター、コンテンツ部分はサイドバーとメインコンテンツの2カラムで構成します。スマートフォンでは1コラムで表示し、サイドバーより優先度の高いメインコンテンツを上部に持ってきます。

<p></p>

基本的なレイアウトのHTMLは下記のようになります。今回はモバイルファーストでCSSを書くので、モバイルで表示するためのCSSを書いたあとにデスクトップ用のCSSを追加・上書きします。モバイルファーストの方がコードが少なく無駄のないCSSが書けるのですが、仕事ではデスクトップファーストで書くこともまだまだ多いです。(特にデスクトップのデザイン重視な案件など)ブレイクポイントは768pxとしました。

HTML

<header>ヘッダー</header>

<div class="container">
	<div class="main">メインコンテンツ</div>
	<div class="sidebar">サイドバー</div>
</div>
<!-- /.container -->

<footer>フッター</footer>

CSS

header{
	display: flex;
	padding: 1em;
	flex-direction: column;
	align-items: center;
}
.sidebar, .main, footer{
	padding: 20px;
}
.sidebar{
	background-color: #ccc;
}
.main{
	background-color: #efefef;
}
footer{
	text-align: center;
	background-color: #222;
	color: #fff;
}

@media screen and (min-width : 768px) { /* デスクトップ用CSS */
	header{
		flex-direction: row;
	}
	.container{
		display: flex;
	}
	.sidebar{
		width: 300px;
	}
	.main{
		flex: 1;
		order: 2;
	}
}

モバイルではflexの指定は特には必要ないのですが、動作を確認するために敢えてflexを使ってロゴやグローバルメニューを横中央揃えにしました。display: flex;でheader全体をflexコンテナに設定し、flex-direction: column;で縦並びに、align-items: center;で横中央揃えにしています。

デスクトップではheader内の要素をflex-direction: row;で横並びにします。サイドバーとメインコンテンツを囲むdiv.containerにflexを指定すると、自動的に2カラムが横並びになります。サイドバーを300pxに固定してメインコンテンツにflex:1;を指定すると、flexコンテナ内(.container)のサイドバーを除いた部分(残りの余白)全体にコンテンツが広がります。
HTMLではメインコンテンツがサイドバーの上に書かれているので、このままだとメインコンテンツが左側、サイドバーが右側に来ますが、orderプロパティを使って表示順序を変えました。

次に、ヘッダー内のロゴとグローバルメニュー、メインコンテンツ内のタイル状のコンテンツを詳しく見ていきます。

ヘッダー

HTML

<header>
	<h1 class="logo"><a href="#">K</a></h1>
	<ul class="gnav">
		<li><a href="#">About</a></li>
		<li><a href="#">Work</a></li>
		<li><a href="#">Blog</a></li>
		<li><a href="#">Contact</a></li>
	</ul>
</header>

CSS

header{
	padding: 1em;
	display: flex;
	flex-direction: column;
	align-items: center;
	font-family: 'Marck Script', cursive;
}
.logo{
	margin: 0.5em 0;
	width: 60px;
	height: 60px;
	display: flex;
	align-items: center;
	justify-content: center;
	font-size: 26px;
	background-color: #000;
	border-radius: 50%;
}
.logo a{
	color: #fff;
	text-align: center;
}
.gnav{
	display: flex;
}
.gnav a{
	display: block;
	padding: 10px;
	font-size: 22px;
}

@media screen and (min-width : 768px) { /* デスクトップ用CSS */
	header{
		flex-direction: row;
	}
	.logo{
		margin: 0 auto 0 0;
		}
	.gnav a{
		padding: 10px 22px;
		display: block;
		font-size: 24px;
		border-radius: 4px;
	}
}

ロゴは「K」の文字が円の中で上下左右真ん中揃えで配置されています。h1要素にflexを指定し、align-items: center; justify-content: center;で垂直・水平方向真ん中揃えの指定をします。なんて簡単!!

グローバルメニューはデスクトップでは右揃えになっています。ロゴの右側のみマージンをautoにすると、グローバルメニューが右側に押されて右寄せになります。

タイル状のコンテンツ部分

HTML

<div class="container">
	<div class="main">
	<p>テキスト1</p>

	<ul class="tiles">
		<li>
			<img src="images/xxx.jpg" alt="">
			<p>テキスト</p>
		</li>
		<li>
			<img src="images/xxx.jpg" alt="">
			<p>テキスト</p>
		</li>
		<li>
			<img src="images/xxx.jpg" alt="">
			<p>テキスト</p>
		</li>
		<!-- 以下繰り返し -->
	</ul>
	<p>テキスト2</p>
	</div>
	<!-- /.main -->

	<div class="sidebar">サイドバー</div>
</div>
<!-- /.container -->

CSS

.tiles{
	margin-bottom: 1em;
}
.tiles li{
	margin-bottom: 1em;
	padding: 20px;
	border-radius: 4px;
	background-color: #fff;
}
.container p:not(:last-child){
	margin-bottom: 1.5em;
}

@media screen and (min-width : 768px) { /* デスクトップ用CSS */
	.tiles{
		display: flex;
		flex-wrap: wrap;
	}
	.tiles li{
		margin: 5px;
		width: calc( 33.3% - 10px);
	}
}

モバイルでは1カラムでコンテンツが表示されるので、CSSでの特別な指定はありません。タイル状のコンテンツの上下にpタグで囲まれたテキストが配置されていますが、コンテンツの最下部のpタグのみ下のマージンを消したい場合は、p:not(:last-child){margin-bottom: 1.5em;}と指定すれば、「最下部以外のpタグにマージンを付ける」ことができます。上記のHTMLの例では、最下部の「テキスト2」以外のpタグにマージンが付きます。

デスクトップではタイル状のコンテンツがメインコンテンツの横いっぱいに3つ並び、各タイル状コンテンツの横幅は親要素の幅に合わせて自動伸縮します。親要素のulにflexを指定すると、li要素が自動的にflexアイテム(子要素)になります。写真の下にあるテキスト量はバラバラですが、タイル状コンテンツの縦幅はデフォルトで一番長いテキストに合わせて自動的に調整してくれます。このコンテンツの縦の長さを揃えるために使っていたJavaScriptはもう不要ですね!

各子要素の横幅は親要素の1/3なので、33.3%となりますが、各子要素周りに5pxのマージンを指定しつつ子要素が3つ収まるように横幅を調整するために、calc関数を使って横幅を10px分小さくする指定をしました。
モバイルでコンテンツを2つ並べて表示させたい場合は、.tiles liのwidthに50%を指定すれば2カラムになります。

各ブラウザでの細かい調整はまだ必要ですが、これから使う機会が増えそうなflexboxで色々なレイアウトを試してみたいです。身につけるなら今がチャンスです!