CSS
 Computer >> コンピューター >  >> プログラミング >> CSS

JavaScript不要!CSSだけで作るタブナビゲーションの実装方法

CSSタブは、関連する情報をひとつの見やすい場所にまとめて表示するのに非常に便利なUIコンポーネントです。見た目は、レシピボックスやバインダーに使われるインデックス付きの仕切りタブに似ています。実際に、タブ型ナビゲーションを採用しているウェブサイトの例をいくつか挙げてみましょう。

  • サウスウエスト航空:タブナビゲーションを使い、「フライトチェックイン」「フライト予約」「ホテルの追加」などの操作をユーザーが簡単に切り替えられるようにしています。
  • エンタープライズ(Enterprise):「レンタル」と「購入」の選択や、その他のサービス紹介をタブで切り替えられるようにしています。

これらのサイトを見ながら、このようなUIコンポーネントを使うメリットについて考えてみてください。どんな課題を解決しているのか?また、どのような情報を表示する場合にタブナビゲーションが適しているのか?

タブナビゲーションが適している場面

テキストや情報を意味のある単位ごとに整理し、画面スペースを圧迫せずに表示したいとき、タブナビゲーションは賢い選択肢となります。通常、タブの実装にはJavaScriptやjQuery、Bootstrapなどが使われますが、実はHTMLと純粋なCSSだけでも実装可能です。今回はその方法を詳しく解説していきます。

HTMLのセットアップ

まず、基本的なHTMLの雛形を用意し、bodyの中にプロジェクト全体を包むコンテナを作成します。クラス名は自由につけられますが、ここではclass="tabs"とします。現時点でのHTMLは以下のようになります。

<!DOCTYPE html>
<html lang="ja">
<head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>CSS Tabs</title>
   <style> /* まだCSSは記述しません */ </style>
</head>
<body>
   <div class="tabs"></div>
</body>
</html>

タブの構造を作る

次に、tabsの中に4つのdiv要素を追加し、それぞれにtabというクラス名をつけます。これが今回作成する4つのタブに相当します。各タブには「ラジオボタン(input)」「ラベル(label)」「コンテンツ(content)」の3要素が含まれます。まずは空のコンテナとして骨組みを作りましょう。

<!DOCTYPE html>
<html lang="ja">
<head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>CSS Tabs</title>
   <style> /* まだCSSは記述しません */ </style>
</head>
<body>
   <div class="tabs">
      <div class="tab">
         /* ラジオボタン */
         <input type="radio" id="tab-1" name="tab-group-1" checked/>
         /* inputに対応するラベル */
         <label for="tab-1">Label 1</label>
         /* コンテンツ */
         <div class="content">ここにコンテンツが入ります</div>
      </div>
      <div class="tab">
         <input type="radio" id="tab-2" name="tab-group-1"/>
         <label for="tab-2">Label 2</label>
         <div class="content">ここにコンテンツが入ります</div>
      </div>
      <div class="tab">
         /* 残りの2つも同じ要領で作成しましょう */
      </div>
      <div class="tab"></div>
   </div>
</body>
</html>

contentクラスの中身には好きなコンテンツを入れられますが、1つのタブには関連性のある内容をまとめるのが一般的なベストプラクティスです。

CSSの実装

CSSを書く際のコツは、大きいコンテナから小さいコンテナへと順番にスタイリングしていくことです。動作させるために最低限必要な手順は以下の通りです。

  1. ワイルドカードセレクター(*)にbox-sizing: border-box;を設定します。
  2. メインコンテナ(.tabs)にはdisplay: flex;position: relative;を設定します。display: flexによりタブが横一列に並び、position: relativeはタブのコンテンツを収める境界線(フェンス)のような役割を果たします。

この時点で確認すると、ラジオボタンとコンテンツが並んだ4つのブロックが表示されているはずです。次に、「選択されたタブだけを表示し、他を隠す」仕組みを作っていきます。

ラベルのスタイリング

  1. .tab内のlabelに対して以下のスタイルを設定します。
    • border: 1px solid — お好みの色で枠線を追加
    • padding: 5px 10px; — ラベルテキストの周囲に余白を作る
    • border-radius: 10px 10px 0 0; — 上部だけ角丸にして、伝統的なタブの見た目に近づける

この時点では、ラベルの左側に丸いラジオボタンが見えている状態です。見た目を整えるため、ボタンの機能(checked属性)は保持したまま、丸い部分だけを非表示にします。

  1. セレクター.tab [type='radio']でボタンを選択し、display: none;を設定して非表示にします。

コンテンツの切り替えを実現する

次に、一度に1つのタブのコンテンツだけが表示されるように制御します。

  1. contentのdivを選択し、position: absolute;を設定します。絶対配置にすることで、relativeな親要素内の任意の場所に配置できます。toprightleftbottomプロパティで位置を調整でき、ここではleft: 0;right: 0;を設定します。あわせて枠線を追加し、背景色も不透明な色に設定しておきましょう。
  2. 選択されたタブのz-indexを上げることで、そのパネルを最前面に表示します。これは[type='radio']:checked ~ label ~ .contentというセレクターで実現できます。CSSの間接セレクター(~)を使うことで、「checked状態のラジオボタン」の後にある「ラベル」と「コンテンツ」をまとめて指定できるのです。
  3. 選択中のタブラベルには、背景色を変えてアクティブであることを視覚的に示しましょう。

これで、ユーザーがタブをクリックするたびに、他のパネルのコンテンツを見ることなくタブ間を移動できるようになりました。以上がタブナビゲーションを動作させるための最小限の実装です。ぜひCSSをいろいろといじって、デザインをカスタマイズしてみてください。

完成版コード(ハリーポッター風カラーテーマ)

以下は、ハリーポッターの寮をテーマにしたカラーリングを加えた、実際に動作する完全なコード例です。

<!DOCTYPE html>
<html lang="ja">
<head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>CSS Tabs</title>
   <style>
       * {
           box-sizing: border-box;
       }

       body {
           font-family: 'Roboto', sans-serif;
       }

       .tabs {
           max-width: 700px;
           min-height: 100px;
           margin: 25px 0;
           width: 100%;
           display: flex; /* タブを横並びにする */
           position: relative; /* コンテンツの範囲を制御する */
       }

       .tab label {
           padding: 5px 10px;
           border: 1px solid #ccc;
           cursor: pointer;
           border-radius: 10px 10px 0 0;
       }

       .tab [type='radio'] {
           display: none; /* ラジオボタンを非表示に(checkedかどうかの判定のみに使用) */
       }

       h3 {
           margin: 10px 40px;
       }

       ul {
           list-style-type: none;
       }

       .content {
           padding: 10px;
           border-radius: 0 10px 10px 10px;
           position: absolute;
           left: 0;
           right: 0;
           background: white;
           border: 1px solid #ccc;
       }

       /* 選択されたタブを最前面に表示 */
       [type='radio']:checked ~ label ~ .content {
           z-index: 1;
       }

       [type="radio"]:checked ~ label {
           background: lightgrey;
       }

       /* 寮ごとのカラーテーマ */
       [type='radio'] ~ #gryffindor {
           background: #9c1203;
           color: #e3a000;
       }
       [type='radio'] ~ #ravenclaw {
           background: #0e1a40;
           color: #946b2d;
       }
       [type='radio'] ~ #slytherin {
           background: #033807;
           color: #aaaaaa;
       }
       [type='radio'] ~ #hufflepuff {
           background: #f0c75e;
           color: #372e29;
       }

       .gryffindor { background: #9c1203; color: #e3a000; }
       .slytherin { background: #033807; color: #aaaaaa; }
       .hufflepuff { background: #f0c75e; color: #372e29; }
       .ravenclaw { background: #0e1a40; color: #946b2d; }
   </style>
</head>
<body>
   <div class="tabs">
       <div class="tab">
           <input type="radio" id="tab-1" name="tab-group-1" checked/>
           <label id="gryffindor" for="tab-1">グリフィンドール</label>
           <div class="content gryffindor">
               <h3>グリフィンドールの生徒</h3>
               <ul>
                   <li>ハリー・ポッター</li>
                   <li>ハーマイオニー・グレンジャー</li>
                   <li>ロン・ウィーズリー</li>
                   <li>アルバス・ダンブルドア</li>
                   <li>ケイティ・ベル</li>
                   <li>ネビル・ロングボトム</li>
               </ul>
           </div>
       </div>
       <div class="tab">
           <input type="radio" id="tab-2" name="tab-group-1"/>
           <label id="slytherin" for="tab-2">スリザリン</label>
           <div class="content slytherin">
               <h3>スリザリンの生徒</h3>
               <ul>
                   <li>ドラコ・マルフォイ</li>
                   <li>ナルシッサ・ブラック</li>
                   <li>ルシウス・マルフォイ</li>
                   <li>セブルス・スネイプ</li>
                   <li>トム・リドル</li>
                   <li>ドロレス・アンブリッジ</li>
               </ul>
           </div>
       </div>
       <div class="tab">
           <input type="radio" id="tab-3" name="tab-group-1"/>
           <label id="ravenclaw" for="tab-3">レイブンクロー</label>
           <div class="content ravenclaw">
               <h3>レイブンクローの生徒</h3>
               <ul>
                   <li>リサ・ターピン</li>
                   <li>ルーナ・ラブグッド</li>
                   <li>ギルデロイ・ロックハート</li>
                   <li>ガリック・オリバンダー</li>
                   <li>パドマ・パチル</li>
                   <li>シビル・トレローニー</li>
               </ul>
           </div>
       </div>
       <div class="tab">
           <input type="radio" id="tab-4" name="tab-group-1">
           <label id="hufflepuff" for="tab-4">ハッフルパフ</label>
           <div class="content hufflepuff">
               <h3>ハッフルパフの生徒</h3>
               <ul>
                   <li>セドリック・ディゴリー</li>
                   <li>ニュート・スキャマンダー</li>
                   <li>ニンファドーラ・トンクス</li>
                   <li>ポモーナ・スプラウト</li>
                   <li>スーザン・ボーンズ</li>
                   <li>テディ・ルーピン</li>
               </ul>
           </div>
       </div>
   </div>
</body>
</html>

まとめ

このように、ラジオボタンのchecked状態とCSSの間接セレクター(~)を組み合わせることで、JavaScriptに一切頼らずにタブ切り替え機能を実装できます。軽量で依存関係のないこの手法は、シンプルなサイトや学習用途にぴったりです。ぜひ自分のプロジェクトでも試してみてください。

  1. CSS画像スプライト(Image Sprite)を使ったナビゲーションメニューの作成方法

    Webサイトの表示速度を向上させるテクニックのひとつに「CSS画像スプライト(Image Sprite)」があります。画像スプライトとは、複数の小さな画像を1枚の大きな画像ファイルにまとめておき、CSSのbackground-positionプロパティで必要な部分だけを表示する手法です。 通常、ページ内の画像1枚ごとにHTTPリクエストが発生しますが、スプライト化することでリクエスト数を大幅に削減でき、その結果としてサイトの読み込み時間を短縮できます。特にアイコンなど小さな画像を多数使うナビゲーションメニューと相性の良い技術です。 CSS画像スプライトでナビゲーションメニューを作成する 以下は

  2. HTMLとCSSでサイドバーとメインコンテンツ領域を含むページを作成する方法

    html要素とbody要素の高さ(height)を100%に設定することで、ブラウザ画面いっぱいに広がる流動的なレイアウトのWebページを作成できます。サイドバーとメインコンテンツ領域を左右に並べた2カラム構成にする場合、CSSのdisplayプロパティでtableとtable-cellを活用すると、各カラムの高さが自動的に揃い、背景も最下部まできれいに伸びるため便利です。 コード例 以下の例では、親要素「#parent」にdisplay: table;を指定し、サイドバー「#side」とメイン領域「#main」にそれぞれdisplay: table-cell;を設定しています。幅はサイドバー