HTMLタブ切り替えにおけるHTML構造
html
tab
アクセシビリティ
構造
タブ切り替えの機能は、よくあるUI(ユーザーインターフェース)でもあります。
パッと見ただけで、どんな使い方をするのかがある程度わかるということでも優秀なUIです。
しかしながら、タブ切り替え機能を実装する際にどのようにHTMLを組むことが良いのかを考えていきたいと思います。
タブ切り替え機能(これ以降、タブUIと表記)とは
まず初めにタブUIについて、どのようなものなのかの認識を合わせたいと思います。
タブUIとは、codegridさんの無料記事を参考にしますが、
こちらの記事のような見た目と形をしている物だと思います。
タブによって現在位置を示し、タブに関連した内容をグルーピングして、表示する内容を切り替えて表示する、
これが自分の認識しているタブUIになります。
タブUIに期待する動作
タブUIの動作でタブUIを操作した際に、
「これをしたらこう動くよね」という期待する動作があると思います。
その動作を書き出したいと思います。
その1 タブをクリックすることで表示内容を切り替えることができる
絶対この動作をしないとタブUIとして成立しないので、当たり前の動作になります。
その2 キーボード操作ができる(Tabキーもしくは矢印キーでタブを選択することができる)
アクセシビリティの観点からキーボードで操作できることも必要だと思います。
その3 キーボードによるカーソル移動順を正しくしたい
キーボードでのカーソル移動を タブ→パネル内→タブ→... の順で移動することが順序的には正しいが、
いざ使ってみと、 タブ→タブ→...→パネル内→... なことが多く、
無駄な操作もしくは遠回りさせられていることが多くなってしまっている。
その4 瞬間的に切り替わるのではなく何かしらのアニメーションをしてほしい
タブUIとしての機能とはあまり関係ないところではあるけれども、
切り替わり時におけるアニメーションがあった方が切り替わったことを確認できて良いような気がする。
タブUIのHTML構造
一般的なタブUIのHTML構造
タブUIとしての動作をさせるための最低限の動作としては、
その1、その2を満たしていればそれなりに動くし、期待通りの動きをすると思います。
実際にBootstrapなどが提供しているタブUIはこの2つを満たし、
期待通りに動いています。
その時の基本的なHTML構造は以下のようになります。
※ bootstrapなどのUIにはWAI-ARIAに関する属性が付与されていることがありますが、その点については今回省かせていただいています。
上記のHTML構造であった時、
キーボード操作を行うと、その2を満たした動きをすることができます。
キーボード操作によるフォーカス移動は tabA→tabB→tabC の順に位置が移り変わっていきます。
ですが、
その3の動きを満たすことができていません。
期待する動きとしては、
tabA→panelAのリンクA→tabB→tabC を期待しましたが、
実際は tabA→tabB→tabC→panelAのリンクA の順にフォーカスは移り変わっていきます。
では、その3を満たすHTML構造というのはどのようなものなのでしょうか。
その3のフォーカス遷移を満たすタブUIのHTML構造
このHTML構造でフォーカスの遷移順が意図した通りの順に当たることになりました。
順に遷移するようになった代わりに考えなくてはならないのが、
タブをどうやって水平に横並びさせ、
パネルをどうやって横並びにしたタブの下に表示するかという問題です。
一般的なタブUIの構造は、
元々タブは一つのul要素にグルーピングされていたので、横一列にすることは容易いですし、
パネルはul要素の兄弟要素として配置されているので、
タブが上、パネルが下という配置は問題なくできると思います。
タブUIのcssスタイル解決策
もっといい方法があれば教えていただきたいのですが、
現状で思いつくのが、下記の設定方法になります。
.tabpanel {
position: relative;
padding-top: 2.5rem;
}
.tab {
position absolute;
top: 0;
z-index: 2;
display: flex;
justify-content: center;
align-items: center;
width: calc(100% / 3);
height: 2.5rem;
opacity: .5;
&.active {
z-index: 1;
opacity: 1;
pointer-event: none;
}
&.tab1 {
left: 0;
}
&.tab2 {
left: calc(100% * (1 / 3));
}
&.tab2 {
left: calc(100% * (2 / 3));
}
}
.panel {
display: none;
&.visibled {
display: block;
}
}
上記の表示方法は、
タブ:1つのタブを横幅33%に設定し、3つを横幅いっぱいに並べる
パネル:タブに連動して.visibled の物を表示し、それ以外は非表示にする。
※ あくまで配置のみのCSSで、タブUI自体の装飾(枠線、背景色 etc)は施していません。
なぜこのようなCSSになるのか
このhtml構造でタブを横並びにさせるためには、li要素からはみ出させる必要性があります。
さらに横並びにさせるために文字数に左右させるのではなく、
全体幅に対して均等幅を割り当てることで横並びすることが容易になります。
タブの横幅を文字数によって変えようと、
個別で設定する、もしくはJSで計算して配置する必要性があり、
一気に難易度が上がります。
その4の切り替え時のアニメーションを行おうと思うと、
さらにハードルが上がります。
切り替え時にパネルをアニメーションさせるためには
タブを切り替えた際にパネルの表示方法をアニメーションにするためには、
幾つかの問題を解消しないといけません。
- パネルにアニメーションを加えたいときは
display
プロパティの切り替えでは実現できない display
プロパティを使えない為、パネルとして設定されている要素に高さが出てしまい表示崩れ(縦に長くなる状態)が起こる- パネルの高さを無くすために
position: absolute;
を設定すると、後に続く要素が表示されているパネルの背後に回りこんでてしまう - 表示されているパネルのみ
position: absolute;
が効かないようにすると、アニメーションの時に後に続く要素がタブ位置まで上下してしまう
このような現象が起こることがあります。
JSによる制御が必要になりますが、HTML構造・構成についてなので、
ここではJSの制御方法については触れません。
この問題点をクリアすることで、
タブUIとしての期待通りの動きをし、
キーボード操作によるアクセシビリティの問題点を解消でき、
アニメーションを加えることで少しリッチになった、
タブUIを実装できるのではないかと思います。
タブUIの切り替え実装、JS制御については別の機会に取り上げたいと思います。