タブコンテンツ

タブボタンをクリックすることで、表示する内容を切り替えるタブコンテンツも、CSSだけでできちゃいます。コンテンツの切り替わり方のバリエーションや、タブボタンで表示レイアウトを切り替えるみたいな使い方など、CSSで作るタブコンテンツについてのまとめです:)

CSSで切り替える仕組み

CSSで切り替えを行うためには、ちょっとした下ごしらえが必要なので、まずはその仕組みについて、下の仕組みがよくわかるサンプルのソースコードを見ながら要点を解説です。

HTML

まずはタブボタンと、それに付随するコンテンツを設置します。
タブボタンに<label>を使うのがポイントです:)

<ul class="tabBtn">
	<li><label for="tab-1">タブ1</label></li>
	<li><label for="tab-2">タブ2</label></li>
	<li><label for="tab-3">タブ3</label></li>
	<li><label for="tab-4">タブ4</label></li>
	<li><label for="tab-5">タブ5</label></li>
</ul>
<div class="tabContents">
	<section class="section-1">タブコンテンツ1</section>
	<section class="section-2">タブコンテンツ2</section>
	<section class="section-3">タブコンテンツ3</section>
	<section class="section-4">タブコンテンツ4</section>
	<section class="section-5">タブコンテンツ5</section>
</div>

次に、コンテンツを切り替えるスイッチの役割となる<input type="radio">(ラジオボタン)5つ、上のソースコードの手前に設置します。

<input type="radio" name="switch" id="tab-1" checked>
<input type="radio" name="switch" id="tab-2">
<input type="radio" name="switch" id="tab-3">
<input type="radio" name="switch" id="tab-4">
<input type="radio" name="switch" id="tab-5">

name属性の値を統一して、ラジオボタンをひとつのグループにします(ここではswitchに統一しました)。こうすることで、<input type="radio">がラジオボタン然とします、つまりどれかひとつボタンをチェックしたら他のボタンのチェックが外れるようになります。
それから<input>id属性の値を、<label>for属性の値と同じにして、タブボタンとラジオボタンを関連付けます。
最後に、ひとつめの<input>にはchecked属性を付けて、初期状態ではタブコンテンツ1が開いているようにしておきます。

以上で下ごしらえ完了!

CSS

そして、以降の指定が、コンテンツの表示/非表示を切り替えるための仕組みの部分になります。
まずは、タブボタンを切り替えた時の、ボタンのスタイルを指定します。

#tab-1:checked ~ .tabBtn label[for="tab-1"],
#tab-2:checked ~ .tabBtn label[for="tab-2"],
#tab-3:checked ~ .tabBtn label[for="tab-3"],
#tab-4:checked ~ .tabBtn label[for="tab-4"],
#tab-5:checked ~ .tabBtn label[for="tab-5"] {
	background: #dc6688;
}

1行めを分解して見てみます。

#tab-1:checked
id属性がtab-1で、チェックされている要素。
~
~チルダ(一般兄弟結合子)と言って、この記号を挟んで、左側のセレクタに後続する兄弟要素(同じ階層にある要素)である右側のセレクタを選択する。
.tabBtn
class属性がtabBtnの要素。
label[for="tab-1"]
for属性がtab-1のlabel要素。

まとめると、「チェックされている#tab-1要素に後続する、同じ階層にある.tabBtn要素の中の、for属性がtab-1のlabel要素」にbackground: #dc6688を指定するって事になります。
要するに「1つめのラジオボタンがチェックされてる時は、1つめのタブボタンの背景を赤くする」ということ;D

1つめのラジオボタンがcheckedの時は、1つめのタブボタンの色が変わる

タブボタンを切り替えた時のコンテンツのスタイルもタブボタンと同じ要領で、「チェックされている#tab-1要素に後続する、同じ階層にある.tabContents要素の中の、.section-1要素」というように、タブコンテンツを特定します。

.tabContents section {
	opacity: .1;
}
#tab-1:checked ~ .tabContents .section-1,
#tab-2:checked ~ .tabContents .section-2,
#tab-3:checked ~ .tabContents .section-3,
#tab-4:checked ~ .tabContents .section-4,
#tab-5:checked ~ .tabContents .section-5 {
	opacity: 1;
	background: white;
}

チェックされていない時は透明(ここでは仕組みが見えるように半透明)にしておき、チェックされている時は不透明にすることで、表示/非表示を切り替えてるって寸法です;)

:targetを使ってタブコンテンツ

上の「仕組みがよくわかるサンプル」では、ラジオボタンと:checked擬似クラスを使ってコンテンツの表示/非表示を切り替えてましたが、アンカーリンクの仕組みを使っても、同じように切り替える事ができます。

例えばURLの末尾に#contents-1と付けてリンクすると、ページ内の<div id="contents-1">の位置へリンクする事ができますよね。id属性を持った要素はすべてアンカーポイントとなって、その要素の場所へリンクできるようになります。
そんなアンカーリンクされている要素に、スタイルを適用する事ができるのが:target疑似クラス
以下のように指定すれば、URLの末尾が#contents-1としてアクセスした時に、contents-1というid属性を持った要素を赤いボーダーで囲みます。

#contents-1:target {
	border: 2px solid #dc6688;
}

URLを利用してスタイルを適用しているので、アンカーリンクする度に特定の要素のスタイルを切り替えることが可能です。しかもURLが切り替わるから、ブラウザの戻るボタンで履歴を辿る事もできちゃいます。タブコンテンツの内容が濃い場合にはこちらの方法が持ってこいかもしれませんねー:D

URL末尾の#ハッシュの値によって、タブボタンの色が変わる

先ほどの、仕組みがよくわかるサンプル:checkedで切り替えてた部分を、:targetで切り替わるように修正してみましょう。

HTML

<input type="radio">だったところを<div>に置き換えます。あくまでスイッチの役割を担う空っぽdiv要素になります。id属性はそのままに、name属性の代わりにclass属性でswitchという値を付与しました。

<input type="radio" name="switch" id="tab-1" checked>
	⇓
<div id="tab-1" class="switch"></div>
input要素をdiv要素に変える

タブボタンは<label>から<a>に置き換えて、for属性でinput要素と紐付けてたところを、今度はhref属性にして、前述の<div>へそれぞれリンクするようにします。

<li><label for="tab-1">タブ1</label></li>
	⇓
<li><a href="#tab-1">タブ1</a></li>
label要素をa要素に変える

CSS

アンカーをクリックすると、ウィンドウの位置がその要素の位置まで移動しちゃいますが、その要素にdisplay: noneを指定すれば移動しなくなります。

.switch {
	display: none;
}
ウィンドウ位置を移動させないための指定

あとは、HTMLに倣ってlabelだったところをaに、forだったところをhrefに、:checkedだったところを:targetに置き換えれば完了ー!

.tabBtn li label { ... }
.tabBtn li label:hover { ... }
	⇓
.tabBtn li a { ... }
.tabBtn li a:hover { ... }
labelaに置き換え
#tab-1:checked ~ .tabBtn li [for="tab-1"] { ... }
	⇓
#tab-1:target ~ .tabBtn li [href="#tab-1"] { ... }
:checked:targetに、forhrefに置き換え
#tab-1:checked ~ .tabContents .section-1 { ... }
	⇓
#tab-1:target ~ .tabContents .section-1 { ... }
:checked:targetに置き換え

いくつかタブを切り替えた後でブラウザの戻るボタンを押してみてください。URLを移動することでタブの表示を切り替えてるので、タブ切り替えが履歴として残るため、切り替える前のタブに戻ることができるんですね;)

アニメーションして切り替わる

タブコンテンツにコンテンツを入れてみました。

タブコンテンツも、マウスオーバーエフェクトの時みたく、transitionを使って切り替わり方をアレンジすれば、印象的な表現ができちゃいます:)

スライドして切り替わる

タブボタンの切り替えに合わせて、<div class="tabContents">の位置を上下にズラせば、スクロールコンテンツみたいなものもお手のもの。

タブボタンに対応するタブコンテンツの位置

上図のように、あらかじめtransform: translateY()で、タブボタンに対応するコンテンツの位置を指定しておきます。例えば下記なら、「タブ2」がチェックされてる時には、.tabContentsを上へ20%ズラす、ということ。.tabContents全体の高さを100%とした20%分。

#tab-2:checked ~ .tabContents {
	transform: translateY(-20%);
}

これをタブコンテンツ分(このサンプルでは5つ)用意し、transitionを適用すれば、上下にスライドしながらコンテンツが切り替わるようになります。

あれれ…、タブコンテンツがタブボタンの上にかぶさってタブボタンが押せなくなっちゃう…X(。。
こんな時は.tabBtnz-indexを指定して、手前に配置すれば安心。

タブボタンをタブコンテンツより手前の階層に
.tabBtn {
	position: relative;
	z-index: 1;
}

z-indexpositionプロパティstatic以外の値が指定してある要素でないと効果がないので、position: relativeも一緒に指定。

無事タブボタンが押せるようになりました:D

横にスライドして切り替わる

タブコンテンツを横並びにして、transform: translateX()で横へズラせば、横スライドもお手のもの。

.tabContentsの横幅20%分ずつスライドする

.tabContentsの横幅をウィンドウ幅5つ分(500%)にして、その中にタブコンテンツを横並びにします。そのままだとスクロールバーが出てしまうので、全体を包む要素(ここではbody要素)overflow: hiddenを指定して、スクロールバーを出さないようにすればできあがり。

表示モード切り替え

ここまでは、いくつかのコンテンツをタブボタンで切り替えてましたが、タブボタンのON/OFFで、同一コンテンツのスタイルを変えるようにすれば、表示モード切り替えみたいな事もできます。

ここでは、「画像とテキスト全部入りのレイアウト」、「画像が主役のレイアウト」、「テキストが主役のレイアウト」の3タイプの表示モードを、タブボタンで切り替えてみます。

下記のような記述で、各モード専用のスタイルを用意しておけば、チェックされているタブボタンに合わせて、指定したスタイルが適用される仕組みです。

#normalList:checked ~ .menu elements {
	/* 全部入り用のスタイル */
}
#imageList:checked ~ .menu elements {
	/* 画像が主役用のスタイル */
}
#textList:checked ~ .menu elements {
	/* テキストが主役用のスタイル */
}

アニメーションを加える

上のサンプルだと、transitionを指定してる所の、前のモードのスタイルがちょっと見えちゃったり、モードの切り替わり方がちょっとかっこわるいですよね…。もうちょっとスマートに、フェードイン・アウトで切り替わるようにしたいです。
以下のように、ちょっと間を置いてからフェードインするアニメーションを用意して、タブボタンが:checkedになった時に一度だけ再生するようにしてみます。

@keyframes fadeIn {
	from, 30% { opacity: 0; }
	to { opacity: 1; }
}
30%時点までは透明で、そこからゆっくり不透明になる

このアニメーションを、チェックされた時のコンテンツに適用します。

input:checked ~ .menu {
	animation: fadeIn 1s;
}

ページが開いた時に一度だけフェードインしますが、タブボタンで切り替える時には、アニメーションが再生されませんね…:(:checkedされるタブが切り替わっても「fadeIn」というアニメーションはすでに再生された後なので、同じ要素に二度は適用されないみたいです…。
そこで、下のサンプルでは、まったく同じアニメーションをもう2つ違う名前で用意して、「画像が主役の」と「テキストが主役の」には別のアニメーション名を指定し直します。

input:checked ~ .menu {
	animation: fadeIn 1s;
}
#imageList:checked ~ .menu {
	animation-name: fadeIn2;
}
#textList:checked ~ .menu {
	animation-name: fadeIn3;
}
@keyframes fadeIn {
	from, 30% { opacity: 0; }
	to { opacity: 1; }
}
@keyframes fadeIn2 {
	from, 30% { opacity: 0; }
	to { opacity: 1; }
}
@keyframes fadeIn3 {
	from, 30% { opacity: 0; }
	to { opacity: 1; }
}

チェックされるタブが変わる度に再生するアニメーションも切り替えることで、タブを切り替える度にアニメーションが再生されるようになりましたね:D