icon-attention デザイン新しくしました。

icon-calendar 2021年2月21日

CSSのみでタブ切り替え

■ソースコード全体

See the Pen
CSSのみでタブ切り替え
by ささ (@mygod877)
on CodePen.

■仕組み

以下の3つの性質を利用することによって、タブ切り替え機能を実現する。

1.ラジオボタンの性質

ラジオボタン<input type="radio">は複数の要素に同じ名前を付けたときに、
必ず一つだけが選択されるという性質を持つ。

以下のラジオボタンは最初に1が選択されており、2をクリックすると
1の選択が解除されて2にチェックが付く。

1: 2: 3:

2.ラベルタグの性質

ラベルタグ<label>はfor属性を持ち、inputタグのid名と合わせることで、
ラベルタグをクリックしてもinputタグをチェック状態にすることができる。

<label for="test">ここをクリックしてもチェック状態になる</label>
<input type="checkbox" id="test">


3.CSSセレクタ「:checked」と「+」の性質

セレクタ:checkedを付けると、その要素がチェックされている
状態のときのみスタイルを適用する。
セレクタA + Bとすることで、要素Aに隣接している要素Bのみに
スタイルを適用する。

この3つを組み合わせ以下のような実装を行う。

  • ラベルタグをタブにする
  • ラジオボタンのinputタグとタブで切り替えるコンテンツのタグを隣接させる
  • inputタグを非表示にし、チェックされたinputタグに隣接したコンテンツタグのみ表示する

■コード解説

〇HTML

タブ1の構成要素は3-7行目の以下のとおりである。

  <input class="trigger" type="radio" id="tab1" name="tab" checked>
  <label class="tab" for="tab1">タブ1</label>
  <div class="contents">
    <p>タブ1の内容</p>
  </div>

上記の説明の通り、ラジオボタンの<input>、タブを表す<label>
タブコンテンツの<div>が並んでいる。
この時の注意点は以下のとおりである。

  • <input>のid属性値と<label>のfor属性値を一致させる
  • 切りかえる全てのタブの<input>のname属性値を同じものにする
  • 初期値として表示させるコンテンツの<input>にchecked属性を付与する

〇CSS

まず、全体を囲む.tab-contentsに対するスタイルを記述する。

.tab-contents {
  display: flex;
  flex-wrap: wrap;
}

HTMLは基本的に記述したタグを上から順番に表示していくため、
そのまま表示させると以下のようになる。

これは記述の順番が、
タブ1 > コンテンツ1 > タブ2 > コンテンツ2 > タブ3 > コンテンツ3
となっているからである。

これを解消するために、flexboxと指定し、各タブにorder: -1を設定する。
そこ以外は見た目に関するスタイルであり、タブ機能には特に関係ない。

.tab {
  border-left: 1px solid #52616b;
  border-top: 1px solid #52616b;
  padding: 3px 15px;
  cursor: pointer;
  user-select: none;
  transition: all 0.2s;
  order: -1;
}
.tab:last-of-type {
  border-right: 1px solid #52616b;
}

次に、<input>はタブ切り替えのトリガーの機能しか持たないため、
非表示(display: none)にしておく。また、タブコンテンツも非表示にする。

.trigger {
  display: none;
}

.contents {
  display: none;
  width: 100%;
  background-color: #52616b;
  color: #f0f5f9;
  padding: 10px
}

最後に、チェックされた<input>に隣接した要素のスタイルを記述する。
選択されたタブの色を変更し、コンテンツを
表示する設定(display: block)に上書きする。

.trigger:checked + .tab {
  background-color: #52616b;
  color: #f0f5f9;
}
.trigger:checked + .tab + .contents {
  display: block;
}