タブを切り替えると、選択中のタブに合わせて下線が滑らかに移動する方法を紹介します。 タブの下に青いラインを配置し、クリックしたタブの位置と横幅に合わせて下線をアニメーションさせます。 下線の移動と同時に、対応するコンテンツも切り替わります。
今回のデモでは、「概要」「特徴」「使い方」「サポート」の4つのタブを用意しています。 タブをクリックすると、下線が現在の位置から選択したタブの位置まで移動し、 タブの横幅に合わせて長さも変化します。 また、左右の矢印キーで前後のタブ、Homeキーで最初のタブ、 Endキーで最後のタブへ切り替えることもできます。
スマートフォンなどの画面幅が狭い場合は、タブ部分を横スクロールできます。 横スクロールや画面サイズの変更が発生しても、選択中のタブに合わせて下線の位置と横幅が調整されます。 タブと下線の動きを連動させることで、現在選択している項目を視覚的に確認できます。
デモ
タブを切り替えると、選択中のタブに合わせて下線がスムーズに移動します。
選択中のタブに合わせて、タブの下にある青い下線がスムーズに移動します。
タブの位置と横幅を取得し、下線の位置と長さを選択したタブに合わせて変更します。
タブはクリックのほか、左右の矢印キー、Homeキー、Endキーでも切り替えられます。
画面幅が狭い場合はタブ部分を横スクロールでき、スクロール後も選択中のタブに下線が合うように調整します。
概要・特徴・使い方・サポートの各タブをクリックすると、青い下線が選択したタブの位置へスムーズに移動し、対応する内容へ切り替わります。
コードをコピーして使おう!
<!DOCTYPE html>
<html lang="ja">
<head>
<!-- 文字コード -->
<meta charset="UTF-8">
<!-- スマートフォン対応 -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- ページタイトル -->
<title>下線アニメーション付きタブ切り替え</title>
<!-- CSSファイル -->
<link rel="stylesheet" href="style.css">
</head>
<body>
<!-- 下線アニメーション付きタブ切り替え全体 -->
<div class="animated-tab-underline_wrap">
<!-- タブ部分 -->
<div class="animated-tab-underline_tabarea">
<!-- タブ一覧 -->
<div
class="animated-tab-underline_tabs"
role="tablist"
aria-label="表示内容">
<!-- 概要タブ -->
<button
class="animated-tab-underline_tab is-active"
id="animated-tab-underline-overview"
type="button"
role="tab"
aria-controls="animated-tab-underline-panel-overview"
aria-selected="true"
tabindex="0"
data-tab="overview">
概要
</button>
<!-- 特徴タブ -->
<button
class="animated-tab-underline_tab"
id="animated-tab-underline-feature"
type="button"
role="tab"
aria-controls="animated-tab-underline-panel-feature"
aria-selected="false"
tabindex="-1"
data-tab="feature">
特徴
</button>
<!-- 使い方タブ -->
<button
class="animated-tab-underline_tab"
id="animated-tab-underline-usage"
type="button"
role="tab"
aria-controls="animated-tab-underline-panel-usage"
aria-selected="false"
tabindex="-1"
data-tab="usage">
使い方
</button>
<!-- サポートタブ -->
<button
class="animated-tab-underline_tab"
id="animated-tab-underline-support"
type="button"
role="tab"
aria-controls="animated-tab-underline-panel-support"
aria-selected="false"
tabindex="-1"
data-tab="support">
サポート
</button>
<!-- 選択中のタブ位置へ移動する下線 -->
<span
class="animated-tab-underline_indicator"
aria-hidden="true">
</span>
</div>
</div>
<!-- 概要コンテンツ -->
<div
class="animated-tab-underline_panel is-active"
id="animated-tab-underline-panel-overview"
role="tabpanel"
aria-labelledby="animated-tab-underline-overview"
data-panel="overview">
<!-- コンテンツタイトル -->
<div class="animated-tab-underline_panel-title">
概要
</div>
<!-- コンテンツ本文 -->
<p class="animated-tab-underline_panel-text">
選択中のタブに合わせて、タブの下にある青い下線がスムーズに移動します。
</p>
</div>
<!-- 特徴コンテンツ -->
<div
class="animated-tab-underline_panel"
id="animated-tab-underline-panel-feature"
role="tabpanel"
aria-labelledby="animated-tab-underline-feature"
data-panel="feature">
<!-- コンテンツタイトル -->
<div class="animated-tab-underline_panel-title">
特徴
</div>
<!-- コンテンツ本文 -->
<p class="animated-tab-underline_panel-text">
タブの位置と横幅を取得し、下線の位置と長さを選択したタブに合わせて変更します。
</p>
</div>
<!-- 使い方コンテンツ -->
<div
class="animated-tab-underline_panel"
id="animated-tab-underline-panel-usage"
role="tabpanel"
aria-labelledby="animated-tab-underline-usage"
data-panel="usage">
<!-- コンテンツタイトル -->
<div class="animated-tab-underline_panel-title">
使い方
</div>
<!-- コンテンツ本文 -->
<p class="animated-tab-underline_panel-text">
タブはクリックのほか、左右の矢印キー、Homeキー、Endキーでも切り替えられます。
</p>
</div>
<!-- サポートコンテンツ -->
<div
class="animated-tab-underline_panel"
id="animated-tab-underline-panel-support"
role="tabpanel"
aria-labelledby="animated-tab-underline-support"
data-panel="support">
<!-- コンテンツタイトル -->
<div class="animated-tab-underline_panel-title">
サポート
</div>
<!-- コンテンツ本文 -->
<p class="animated-tab-underline_panel-text">
画面幅が狭い場合はタブ部分を横スクロールでき、スクロール後も選択中のタブに下線が合うように調整します。
</p>
</div>
</div>
<!-- JavaScriptファイル -->
<script src="script.js"></script>
</body>
</html>
コードをコピーする場合 使用するコードのタブを選び、「このタブをコピー」をクリックすると、現在表示中のコードをコピーできます。 サンプル一式を取得する場合 HTML・CSSなどすべてのファイルが必要な場合は、「サンプル一式をダウンロード」をクリックしてください。
Q ダウンロードしたけど、これをネット上で動かすにはどうするの?
Googleアカウントがあれば、InfinityFreeで無料サーバーを作成して、ダウンロードしたサンプルをネット上で動かせます。
InfinityFreeを初めて利用する場合は①から、すでにサーバーを作成している場合は②へ進んでください。
ファイル構成と設置方法
下線アニメーション付きタブ切り替えは、HTML・CSS・JavaScriptの3つのファイルで動作します。 HTMLには4つのタブと対応するコンテンツ、選択位置を示す下線を配置しています。 CSSではタブの横並びや下線のアニメーションを設定し、 JavaScriptでは選択中のタブの位置と横幅を計算して、下線の表示を更新しています。
sample/
├── index.html
├── style.css
└── script.js
各ファイルの役割
index.htmlには、「概要」「特徴」「使い方」「サポート」の4つのタブと、
それぞれに対応するコンテンツを記述しています。
また、animated-tab-underline_indicatorを配置し、
選択中のタブの下に移動するラインとして使用しています。
style.cssでは、タブの横幅・余白・文字色・下線の太さ・アニメーション速度などを設定しています。
script.jsでは、クリックやキーボード操作によるタブの切り替え、
下線の位置と横幅の更新、横スクロールや画面サイズ変更時の位置調整を行っています。
設置方法・使い方
「サンプル一式をダウンロード」をクリックしてZIPファイルを保存し、展開してください。
sampleフォルダ内のindex.html・style.css・script.jsを
同じ階層に配置し、index.htmlをブラウザで開くとタブ切り替えが表示されます。
「概要」「特徴」「使い方」「サポート」のいずれかをクリックすると、
対応するコンテンツが表示され、青い下線が選択したタブの下へ移動します。
キーボードでは左右の矢印キーで前後のタブへ移動し、
Homeキーで最初、Endキーで最後のタブを選択できます。
タブとコンテンツを関連付ける方法
index.htmlでは、各タブのdata-tabと、
対応するコンテンツのdata-panelに同じ値を設定しています。
次のコードは「概要」タブと、そのコンテンツの開始部分です。
<!-- 概要タブ -->
<button
class="animated-tab-underline_tab is-active"
id="animated-tab-underline-overview"
type="button"
role="tab"
aria-controls="animated-tab-underline-panel-overview"
aria-selected="true"
tabindex="0"
data-tab="overview">
概要
</button>
<!-- 概要コンテンツ -->
<div
class="animated-tab-underline_panel is-active"
id="animated-tab-underline-panel-overview"
role="tabpanel"
aria-labelledby="animated-tab-underline-overview"
data-panel="overview">
<!-- コンテンツタイトル -->
<div class="animated-tab-underline_panel-title">
概要
</div>
<!-- コンテンツ本文 -->
<p class="animated-tab-underline_panel-text">
選択中のタブに合わせて、タブの下にある青い下線がスムーズに移動します。
</p>
</div>
data-tab="overview"とdata-panel="overview"が対応しているため、
「概要」タブを選択すると概要のコンテンツが表示されます。
他のタブもfeature・usage・supportの値で関連付けています。
タブの表示文字はbutton要素内、
コンテンツの文章は対応するanimated-tab-underline_panel-text内で変更できます。
data-tabやdata-panelの値を変更する場合は、
対応する組み合わせを一致させてください。
また、タブのaria-controlsとパネルのid、
パネルのaria-labelledbyとタブのidも対応させます。
選択中のタブに合わせて下線を移動する仕組み
script.jsのmoveAnimatedTabUnderlineIndicator()関数では、
選択中のタブとタブ一覧の位置を取得し、
下線の左端位置と横幅を更新しています。
// 選択中タブの位置と横幅に下線を合わせる
function moveAnimatedTabUnderlineIndicator(activeTab){
// 選択中タブの位置とサイズを取得
const tabRect =
activeTab.getBoundingClientRect();
// タブ一覧の位置とサイズを取得
const tabsRect =
animatedTabUnderlineTabsWrap.getBoundingClientRect();
// タブ一覧の左端を基準に選択中タブの位置を計算
const left =
tabRect.left - tabsRect.left;
// 下線を選択中タブの位置へ移動
animatedTabUnderlineIndicator.style.left =
left + "px";
// 下線の横幅を選択中タブと同じ横幅へ変更
animatedTabUnderlineIndicator.style.width =
tabRect.width + "px";
}
getBoundingClientRect()は、要素の画面上の位置やサイズを取得する処理です。
tabRect.leftからtabsRect.leftを引くことで、
タブ一覧の左端を基準とした選択中タブの位置を求めています。
計算した位置を下線のstyle.leftへ、
選択中タブの横幅をstyle.widthへ設定するため、
タブの幅が異なる場合でも、そのタブに合わせて下線の長さが変わります。
下線の太さ・色・移動速度を変更する方法
style.cssの.animated-tab-underline_indicatorでは、
下線の見た目とアニメーションを設定しています。
/* 選択中のタブ位置へ移動する下線 */
.animated-tab-underline_indicator{
position:absolute; /* タブ一覧を基準に配置 */
left:0; /* JavaScriptで選択中タブの位置へ変更 */
bottom:-1px; /* タブ一覧の境界線へ下線を重ねる */
width:0; /* JavaScriptで選択中タブの横幅へ変更 */
height:3px; /* 下線の太さ。値を大きくすると太くなる */
border-radius:999px; /* 下線の両端を丸くする */
background:#0b6bff; /* 下線の色 */
pointer-events:none; /* 下線がクリック操作を妨げないようにする */
transition:
left .3s ease,
width .3s ease;
/*
下線の位置と横幅を0.3秒で変化させる。
値を大きくするとゆっくり、小さくすると速く移動する。
*/
}
height:3px;は下線の太さです。
数値を大きくすると太く、小さくすると細くなります。
background:#0b6bff;を変更すると下線の色を調整できます。
transitionでは、下線の位置を表すleftと
横幅を表すwidthを、それぞれ0.3秒で変化させています。
移動を遅くしたい場合は両方の.3sを大きくし、
速くしたい場合は小さくしてください。
なお、下線の位置と横幅はJavaScriptで更新されるため、
CSSのleft:0;とwidth:0;は初期値として使用しています。
タブとコンテンツの選択状態を切り替える方法
script.jsのactivateAnimatedTabUnderline()関数では、
すべてのタブとコンテンツの選択状態を解除したあと、
指定されたタブと対応するコンテンツを選択状態にしています。
次のコードは、対応するコンテンツを取得して表示し、
下線を移動する部分です。
// data-tabと同じdata-panelを持つコンテンツを取得
const targetPanel =
document.querySelector(
'.animated-tab-underline_panel[data-panel="' +
target +
'"]'
);
// 対応するコンテンツが存在する場合だけ表示
if(targetPanel){
targetPanel.classList.add("is-active");
}
// 下線を選択したタブの位置へ移動
moveAnimatedTabUnderlineIndicator(
targetTab
);
targetには、選択したタブのdata-tabの値が入ります。
その値と一致するdata-panelを持つコンテンツを検索し、
is-activeクラスを追加して表示しています。
コンテンツの表示・非表示はstyle.cssの
.animated-tab-underline_panelと
.animated-tab-underline_panel.is-activeで制御しています。
タブの切り替え後にmoveAnimatedTabUnderlineIndicator()を呼び出すことで、
コンテンツの表示と下線の移動を連動させています。
キーボード操作による切り替え
script.jsでは、各タブにkeydownイベントを登録しています。
右矢印キーでは次のタブ、左矢印キーでは前のタブを選択し、
Homeキーでは最初、Endキーでは最後のタブへ移動します。
最後のタブで右矢印キーを押すと最初に戻り、
最初のタブで左矢印キーを押すと最後へ移動します。
移動先のタブにフォーカスを合わせたあと、
activateAnimatedTabUnderline()で表示と下線を更新しています。
横スクロールや画面サイズ変更に合わせて下線を調整する方法
script.jsでは、タブ部分の横スクロール時と
ウインドウサイズ変更時にも下線の位置を再計算しています。
横スクロール時の処理は次のとおりです。
// タブ部分を横スクロールしたときに下線位置を再計算
animatedTabUnderlineTabArea.addEventListener(
"scroll",
function(){
// 現在選択されているタブを取得
const activeTab =
document.querySelector(
".animated-tab-underline_tab.is-active"
);
// 選択中タブが存在する場合だけ下線位置を調整
if(activeTab){
moveAnimatedTabUnderlineIndicator(
activeTab
);
}
}
);
scrollイベントが発生すると、
現在のis-activeクラスを持つタブを取得し、
moveAnimatedTabUnderlineIndicator()を実行しています。
ウインドウサイズ変更時もresizeイベントで同じ関数を呼び出すため、
タブの横幅や配置が変わった場合に下線の位置を調整できます。
また、ページ表示時にも選択中のタブを取得して下線を配置しています。
レスポンシブ対応
style.cssでは、タブ切り替え全体に
width:100%;とmax-width:700px;を設定しています。
これにより、広い画面では最大700pxの横幅で表示し、
狭い画面では設置先の横幅に合わせて縮小します。
タブ部分にはoverflow-x:auto;を指定しているため、
4つのタブが横幅に収まらない場合は、タブ部分だけを横スクロールできます。
タブ名はwhite-space:nowrap;で折り返さず、
min-widthで各タブの最小横幅を確保しています。
/* 画面幅640px以下 */
@media (max-width:640px){
/* タブ切り替え全体 */
.animated-tab-underline_wrap{
padding:24px 18px; /* スマートフォン時の内側余白 */
}
/* 各タブ */
.animated-tab-underline_tab{
min-width:110px; /* スマートフォン時のタブ最小横幅 */
min-height:48px; /* スマートフォン時のタブ最小高さ */
padding:12px 16px; /* スマートフォン時の内側余白 */
font-size:14px; /* スマートフォン時の文字サイズ */
}
/* 各コンテンツ */
.animated-tab-underline_panel{
min-height:170px; /* スマートフォン時のコンテンツ最小高さ */
padding:20px 16px; /* スマートフォン時の内側余白 */
}
/* コンテンツ内のタイトル */
.animated-tab-underline_panel-title{
font-size:17px; /* スマートフォン時のタイトル文字サイズ */
}
}
画面幅が640px以下になると、
タブの最小横幅は120pxから110px、最小高さは52pxから48pxに変更されます。
文字サイズは16pxから14pxに縮小され、
コンテンツの最小高さも190pxから170pxに調整されます。
スマートフォンでタブの横幅を広げたい場合は、
min-width:110px;の数値を大きくしてください。
コンテンツの表示領域を広げたい場合は、
min-height:170px;を大きくします。
レスポンシブ設定を切り替える画面幅は、
@media (max-width:640px)の数値で変更できます。
コメント