タブメニューをスマホでも
左右にスワイプできる方法でレスポンシブ対応したタブメニューです。Androidのブラウザで試してみて下さい。
22-04-02現在、まだカットアンドトライで機能調整中。
作成要件
タブメニューをスマホでもそのまま使いたい、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がベンダー依存ですので、将来が気になるところです。
スワイプ
スマホでのスクロールはスワイプ操作になり、この点はパソコンより使いやすい。
パソコンのタッチパネルディスプレイも然り。
パソコンの場合はスクロールバーのマウスドラッグ、またはスクロール領域がアクティブなら矢印キーでの操作なります。
スクロール領域がアクティブならマウスドラッグのスクロール出来るようにしましたが、これを認識して利用する人は少なさそう。
左右や上下にスクロるさせるナビは、スマホとパソコンで設置出来るようにしました。
左右のぼかし
タブメニューの左右の端に、メニューが左右に隠れてあるぞという連想できるボカシをかぶせました。
注意としては、上にかぶせますので、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の糖衣構文)で記述したモジュールですので比較的(落書き人にとっては)簡単に応用が聴きます。
写真のスライド
あとで記述して公開
タブ幅不揃いの場合
あとで記述して公開
縦スライド
あとで記述して公開