本文へスキップ

下線スライドタブ

選択中タブの下に下線がスッと横移動するタブUI。現在地が直感的に伝わり、内容も切り替わる。

プレビュー

クリック

操作クリック/タップで動きます。

使いどころ

2〜5個程度の並列した切替先(概要/仕様/レビューのような同列コンテンツ)を1画面に収めたいときに向く。下線が横移動することで「今どこにいるか」と「どちらへ動いたか」の両方が伝わるため、設定画面やプロフィール画面のセクション切替など、ユーザーが何度も行き来する場所で効果が大きい。逆に、タブの数が可変で6個を超えたり、ラベルが長文になる場合には向かない。flex:1で均等割りする実装のため、タブが増えるほど1個あたりの幅が狭くなり、折り返しや文字の潰れが起きる。そうした場面は横スクロール式のタブか、ドロップダウンでの選択に切り替えるべきだ。また、パネルの中身が大きく異なる(フォームとグラフなど)場合は、切替のたびにレイアウトの高さが大きく変わり、下線のアニメーションよりもガクつきの方が目立つので注意する。

仕組み

下線要素 .tab-ink を tab-row 内に1つだけ置き、クリックされたタブの offsetLeft と offsetWidth を読んでその値を left/width に反映させることで、タブ間を移動しているように見せる。left と width は両方 transition の対象になっており、幅が違うタブへ移動するときは伸び縮みしながら滑る。中身の切替は各タブ・各パネルの is-active クラスを付け替えるだけの単純な仕組みで、パネルは display:none で完全に非表示にする(opacity操作ではないため、非表示中はレイアウトにも操作可能要素の判定にも影響しない)。フォント読み込み完了時(document.fonts.ready)とウィンドウリサイズ時にも moveInk() を呼び直しており、Webフォントの差し替えでタブ幅が変わったときに下線がずれたまま固定される事故を防いでいる。

実装の注意

offsetLeft/offsetWidth を使う実装は、タブの幅がJSの実行タイミングと実際の描画で食い違うと下線がずれる。典型例はWebフォントの読み込み待ちで、フォント切り替え前の幅で計算した位置がそのまま残ってしまうケースだが、これは document.fonts.ready で手当て済みなので流用時も消さないこと。もう一つは、タブ数が増減するUI(動的にタブを足し引きする管理画面など)で、タブを追加・削除した直後に moveInk(activeTab()) を呼び直す処理が抜けやすい点。呼び忘れると新しいレイアウトに対して古い座標のまま下線が浮く。また、tab-row は display:flex で各 .tab は flex:1 で均等割りしているだけで overflow-x の逃げ場がないため、モバイル幅でタブ数やラベル長を増やすなら、横スクロール可能なコンテナへ作り替える設計変更とセットで検討する必要がある。

アクセシビリティ

現状のマークアップは素の button と div の組み合わせで、WAI-ARIA の Tabs パターンが求める role="tablist"(タブの並び)・role="tab"(各ボタン)・role="tabpanel"(各パネル)・aria-selected・aria-controls と id の対応付けを持っていない。button 要素なのでTabキーでの到達とEnter/Spaceでの選択という最低限の操作性はブラウザ標準の挙動として成立しているが、スクリーンリーダーには「タブの集合であること」も「今どれが選ばれているか」も伝わらない。実装するときはこれらのARIA属性を足したうえで、Tabsパターンが期待する矢印キー(左右)でのタブ間移動も追加するのが望ましい。パネル側は display:none で確実に非表示になっているので、非選択タブの内容がキーボードで誤って触れてしまう心配はない。

調整して使う

触る値は下線の太さ・色・移動速度の3つが中心。デモは2px・#2b50c7・0.28sだが、下線を太く(3〜4px)して角丸を付けると「タブというよりピル型セグメント」に近い印象になる。移動のイージングを cubic-bezier で伸び縮みを強調すると遊び心が出る一方、業務画面では linear に近い方が落ち着く。下線ではなく背景のピル(is-active のタブ全体に色を敷く)に切り替える変化球もあり、その場合は left/width の代わりに transform: translateX() でピル自体を動かす実装になる。タブ数が多い構成に育てる予定があるなら、早い段階で横スクロール対応のレイアウトに置き換えておく方が後の手戻りが少ない。

コード(コピーして使えます)

<div class="tabs">
  <div class="tab-row">
    <button class="tab is-active" data-tab="0">概要</button>
    <button class="tab" data-tab="1">仕様</button>
    <button class="tab" data-tab="2">レビュー</button>
    <span class="tab-ink"></span>
  </div>
  <div class="tab-panels">
    <div class="tab-panel is-active">
      <p>このパーツの概要をここに書きます。使い方がすぐわかるシンプルなタブです。</p>
    </div>
    <div class="tab-panel">
      <p>対応ブラウザ: 最新Chrome / Firefox / Safari。依存ライブラリ: なし。</p>
    </div>
    <div class="tab-panel">
      <p>「現在地がわかりやすい」「アニメが自然」と好評です。</p>
    </div>
  </div>
</div>

タグ

同じカテゴリ「ナビ・リスト操作」のほかのパーツ

関連パーツ