Panda Noir

JavaScript の限界を究めるブログでした。最近はいろんな分野を幅広めに書いてます。

YouTube のスワイプで消せるフロートカードを実装する

↑これを CSS + JS で作りました。フロートカードと呼んでますが、正式名称は分かりません。半モーダルとか bottom drawer とか slidable drawer と呼ぶらしい?

動かせるデモはこちら

実装のポイント: scroll-snap

JS をほぼ使わずに CSS の scroll-snap を使って実装しました。scroll-snap を使うと次のような実装ができます。

  • スワイプが中途半端だったら元の位置に戻す
  • 一定量を超えたら画面外に移動させて消す

便利ですね。touchstart や touchmove のイベント量を監視してアレコレするよりよほどシンプルです。

scroll-snap はかなり便利

scroll-snap を使うと、カルーセルのようにスクロールした際に特定の位置でピタッと止まるように吸着させられます。

scroll-snap は応用の幅があります。例えば、「スワイプで LIKE」「スワイプで削除」のような機能もカンタンに作れます。ほかの人が作ったデモ。便利ですね。

今回のフロートカードも scroll-snap 応用編に近いですよね。

苦労したポイント

カードの外の部分をスワイプしたときにカードが移動しないようにするのが難しかった

これは、カード外がタップされたら overflow-y: hidden をつけるようにして解決しました。 overflow-y: scroll を消すというやり方だと iPhone の safari でうまく動作しなかったので…

カードを画面外にスワイプさせるのが難しかった

これは、カードの上下にスナップポイントを用意してやることで解消しました。今回初めて scroll-snap 使ったので、思いつくまでに時間がかかりました。

未実装の箇所

実はいくつか未実装の箇所がある。

  • 画面の高さが十分でない時(横画面の時など)に上にスワイプすることでカードを上に伸ばす
  • リストアイテムが多い時のスクロールとの共存

この辺りは素直に scroll-snap を使うだけだと難しい気がします。どうしたらできるんだろ。

まとめ

初めにも張りましたが、動かせるデモはこちらです。ぜひ触ってみてください。結構わけわからないコードになってるので。

scroll-snap について知らなかったのでだいぶ勉強になりました。仕事でカルーセル実装するときに JS で頑張っていたけど、scroll-snap を使っていればもっと楽できたのでは…?とムチャクチャ思いました。

あと、StackBlitz でゴリゴリ初めて書きましたが、微妙にかゆいところに手が届かない感じですね…例えばこのあたり。

  • useState を補完で出すと React.useState になる
  • remove braces from arrow function ができない
  • デフォルトの React テンプレートから作ると import * as React from 'react' が消せない

今回みたいにパッと動くものを作る用途では便利ですが、1時間以上書く場合は少しストレスですね。

みんなもフロートカードを作ってみよう!意外と苦戦するよ!