-->

タブメニュー

 
Web Tips.
Booskanium's
Booskanium's Web Tips.

タブメニューをスマホでも

左右にスワイプできる方法でレスポンシブ対応したタブメニューです。Androidのブラウザで試してみて下さい。
22-04-02現在、まだカットアンドトライで機能調整中。

scrollLeft:

present ix: / top: / left:

作成要件

タブメニューをスマホでもそのまま使いたい、Android版Vivaldiのタブ選択の様な動きで、その為のタブメニューのレスポンシブ対応です。
レスポンシブのお手本はAndroid版のVivaldiのタブ切り替えです。

HTMLとCSS要件は
・タブメニューは
  ├→スクロールするブロックはUL
  ├→タブ部分はLIタグで横並びスクロール
  │ ※縦並びの可能
  └→ULとLIの組み合わせはケースバイケース
・スクロールバーは非表示
  ├→これはデザインを考慮しての事で任意
  └→実現するCSSがベンダー依存で微妙
・LIタグの幅は任意で不定幅も許容
・LIタグのクリックイベントはモジュールにて
・タブメニュー部分の外見はHTML+CSSで自由

JavaScriptのclassモジュール要件は
・ページ中に当モジュール設置は複数可
  └→JavaScriptのクラス記述にて
・モジュールは特定のHTML+CSSに依存しない
  ├→スクロール領域,タブ要素,左右ナビ
  └→上記はインスタンス時に指定
・左右スクロールを制御
・左右スクロールナビはLIタグの任意幅で
・Windowの動的サイズ変更に追従
・スクロールイベントにて追従
・タブ部分のクリックイベントを制御
  ├→アンカーでリンク
  ├→datasetで対応要素のエレメントID指定
  └→後述のモジュールにonプロパティで指定
・パソコンはマウスドラッグでスワイプと同じ動作
  └→この機能は実装予定
・パソコンのタッチパネルディスプレイ
  ├→ポインターイベントで拾うだか?
  └→ブラウザがよきにはからってくれている
・URL引数で開いているタブ指定
  └→multiple pagesの時に活用

左右スライドをスクロール機能にした理由

タブメニューの左右スライドをtransformのtranslateXでも試しました。
これで問題が発覚しました。Windowがズームされている場合のスワイプは、ページスライドが優先で、タブメニュー部分のスライドが出来ないことです。
スクロールなら、ブラウザがスクロールを優先させてくれるので問題有りません。
ただしスクロールバー非表示にしたい場合は、そのCSSがベンダー依存ですので、将来が気になるところです。

左右のナビ

タブメニューの左右に、左右にスライドさせるナビを設けました。
イメージですがsvgをJavaScript内に抱え込んでいます。
この手法ならcssで色を指定できるので至極便利です。

なお、左右移動が端まで達している場合、または移動できる状態の場合に、このナビの表示を変える事も試しましたがくどくなるだけなので未採用。

SVG部分のコードは

<svg version="1.1" preserveAspectRatio="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 515 515">
<g>
<polygon class="petitabArrow02" points="419.916,71.821 348.084,0 92.084,256.005 348.084,512 419.916,440.178 35.742,256.005"></polygon>
</g>
</svg>
です。
“class="petitabArrow02"”部分のクラス属性名はCSSで
.petitabArrow0 { 
	fill: var(--petitTabColorBackground);
}
の様に色を指定する事ができます。

スワイプ

スマホでのスクロールはスワイプ操作になり、この点はパソコンより使いやすい。
パソコンのタッチパネルディスプレイも然り。

パソコンの場合はスクロールバーのマウスドラッグ、またはスクロール領域がアクティブなら矢印キーでの操作なります。
スクロール領域がアクティブならマウスドラッグのスクロール出来るようにしましたが、これを認識して利用する人は少なさそう。

左右や上下にスクロるさせるナビは、スマホとパソコンで設置出来るようにしました。

左右のぼかし

タブメニューの左右の端に、メニューが左右に隠れてあるぞという連想できるボカシをかぶせました。
注意としては、上にかぶせますので、CSSに「pointer-events:none;」を指定して、マウスやタッチの操作を下になるレイヤーに伝えることです。

アンカー

タブメニューにアンカーがあると、これが曲者です。
・スワイプのイベントを止めてしまう。
 ├→アンカー部分はURLのドラッグ&ペースト機能
 └→つまりスワイプにバブリングを止めてしまう
・アンカー部分のが選択されてしまう。
これを防ぐために、アンカーのCSSと、アンカー中のてテキストのCSSに「pointer-events:none;」を指定して、実質的にアンカーの機能を無効にしました。そしてJavaScriptでアンカーの動作をさせる様にしました。
アンカーに限らず、スワイプを拾うブロック上にかぶさっている要素には「pointer-events:none;」を指定してくおかないと、面倒な事象に悩むことが解りました。

条件を限定すればまあまあ

・ピンチアウト(ズーム)で拡大するとページ全体の左右移動。
 ├→スクロールなら要素部分のスクロールが優先になっているのに
 ├→つまりviewportで拡大出来ないようにすれば実用的
 └→Chromeがズームを抑止する方法がかなり煩雑でまら対応できていない
・変な所が選択されてしまう。
 ├→CSSの工夫次第だかちょっと難儀
 └→アンカータグとの相性が悪いので工夫が必要
・タブブウ部分のデザインに拘る場合に上記の件で単純じゃない。
・スワイプ検知は別のモジュールを使っている。
 └→
・低階層よりな制御なのでJavaScriptが難解かもです。

上記の理由で、コピペしただけで、はいKですというレベルにはなっていない。

現時点での課題

・スマホのChromeでピンチズームを抑止
現状はターゲットエレメントの時に、マルチタッチだったら抑止した。
下記をトプレベルの中に書いたらOK、これをモジュールの中で考慮するようにする。
document.documentElement.addEventListener('touchstart', function (event) {
if (event.touches.length > 1) {
event.preventDefault();
}
}, false);

・スワイプイベントを拾うのをクラス継承にする。
https://qiita.com/y_catch/items/9349f4b5180c45f73fa7

・スワイプしなくでもタッチエンドで選択解除

当タブメニュー機能はclass(Prototypeの糖衣構文)で記述したモジュールですので比較的(落書き人にとっては)簡単に応用が聴きます。

写真のスライド

あとで記述して公開

タブ幅不揃いの場合

あとで記述して公開

縦スライド

あとで記述して公開