ストーリー コンポーネントの作成

ウェブで Instagram ストーリーに似たエクスペリエンスを構築する方法の基本的な概要。

この記事では、レスポンシブで、キーボード ナビゲーションをサポートし、ブラウザ間で動作するウェブ向けのストーリー コンポーネントを構築する方法について説明します。

デモ

このストーリー コンポーネントを自分で構築する実践的なデモについては、ストーリー コンポーネントの Codelab をご覧ください。

動画で視聴したい場合は、この投稿の YouTube バージョンをご利用ください。

概要

ストーリー UX の一般的な例としては、Snapchat ストーリーと Instagram ストーリー(もちろん、Fleets も)があります。一般的な UX 用語では、ストーリーは通常、複数の定期購入を操作するためのモバイル専用のタップ中心のパターンです。たとえば、Instagram では、ユーザーが友だちのストーリーを開き、その中の写真を閲覧します。通常、一度に多くの友だちをブロックします。デバイスの右側をタップすると、その友達の次のストーリーにスキップします。右にスワイプすると、別の友だちにスキップします。 ストーリー コンポーネントはカルーセルによく似ていますが、単一次元配列ではなく多次元配列を操作します。各カルーセル内にカルーセルがあるようなものです。🤯

カードを使用して可視化された多次元配列。左から右に紫色の枠線のカードが積み重ねられており、各カードの中には青色の枠線のカードが 1 枚以上あります。リスト内のリスト。
友だちの 1 番目のカルーセル
記事の 2 番目の「積み重ね」カルーセル
✨ リスト内のリスト(別名: 多次元配列)

ジョブに適したツールの選択

まとめると、このコンポーネントはいくつかの重要なウェブ プラットフォーム機能のおかげで、簡単にビルドできました。詳しく見てみましょう。

CSS グリッド

コンテンツを整理する強力な方法が用意されているため、このレイアウトは CSS Grid にとって難題ではありませんでした。

フレンドのレイアウト

主な .stories コンポーネント ラッパーは、モバイルファーストの横向きスクロールビューです。

.stories {
  inline-size: 100vw;
  block-size: 100vh;

  display: grid;
  grid: 1fr / auto-flow 100%;
  gap: 1ch;

  overflow-x: auto;
  scroll-snap-type: x mandatory;
  overscroll-behavior: contain;
  touch-action: pan-x;
}

/* desktop constraint */
@media (hover: hover) and (min-width: 480px) {
  max-inline-size: 480px;
  max-block-size: 848px;
}
Chrome DevTools のデバイスモードを使用して、グリッドによって作成された列をハイライト表示

grid レイアウトを分解してみましょう。

  • モバイルではビューポートを 100vh100vw で明示的に埋め、パソコンではサイズを制限します。
  • / は行テンプレートと列のテンプレートを区切る
  • auto-flowgrid-auto-flow: column に変換されます
  • 自動フロー テンプレートは 100% です。この場合は、スクロール ウィンドウの幅になります。

スマートフォンでは、行サイズがビューポートの高さ、各列がビューポートの幅と考えてください。Snapchat のストーリーと Instagram のストーリーの例を続けると、各列は友人のストーリーになります。スクロールする場所を確保するため、友達のストーリーはビューポートの外側に続くようにします。グリッドでは、友だちストーリーごとに HTML をレイアウトするために必要な列の数が作成され、動的でレスポンシブなスクロール コンテナが作成されます。グリッドにより、効果全体を一元化できました。

重ね置き

各フレンドのストーリーが、ページネーションに対応した状態である必要があります。アニメーションやその他の楽しいパターンを準備するため、スタックを選択しました。スタックという言葉は横から見るのではなく サンドイッチを見下ろしているようなものです

CSS グリッドを使用すると、行と列がエイリアス([story])を共有する単一セルのグリッド(正方形)を定義できます。各子は、そのエイリアスされた単一セルのスペースに割り当てられます。

.user {
  display: grid;
  grid: [story] 1fr / [story] 1fr;
  scroll-snap-align: start;
  scroll-snap-stop: always;
}
.story {
  grid-area: story;
  background-size: cover;
  
}

これにより、HTML で重ね順を制御し、すべての要素をフロー内に維持できます。absolute の配置や z-index については何も行う必要がなく、height: 100%width: 100% でボックスを正しく囲む必要もありません。ストーリー画像のビューポートのサイズは親グリッドですでに定義されているため、これらのストーリー コンポーネントをそのサイズに合わせて指示する必要はありません。

CSS スクロール スナップ ポイント

CSS のスクロール スナップ ポイント仕様では、スクロール時に要素をビューポートに簡単にロックできます。これらの CSS プロパティが存在する前は、JavaScript を使用する必要があり、控えめに言っても、それは非常に面倒でした。その使用方法について詳しくは、Sarah Drasner による Introduction CSS ベースのスクロール スナップ ポイントをご覧ください。

scroll-snap-points スタイルありとなしでの水平スクロール。 設定しない場合、ユーザーは通常どおり自由にスクロールできます。これにより、ブラウザが各アイテムに優しく接触します。
.stories {
  display: grid;
  grid: 1fr / auto-flow 100%;
  gap: 1ch;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  overscroll-behavior: contain;
  touch-action: pan-x;
}
オーバースクロールのある親がスナップ動作を定義します。
子ども
.user {
  display: grid;
  grid: [story] 1fr / [story] 1fr;
  scroll-snap-align: start;
  scroll-snap-stop: always;
}
お子様はスナップ ターゲットになることをオプトインします。

スクロール スナップ ポイントを選択した理由はいくつかあります。

  • 無料のユーザー補助。スクロール スナップポイントの仕様では、デフォルトで左矢印キーと右矢印キーを押すとスナップポイント間を移動すると規定されています。
  • 仕様が進化している。スクロール スナップ ポイントの仕様は常に新機能が追加され、改善されています。つまり、今後もストーリー コンポーネントはますます便利になるでしょう。
  • 実装の容易さ。スクロール スナップ ポイントは、タップ中心の横方向のページネーションのユースケース向けに実質的に構築されています。
  • 自由なプラットフォーム スタイルの慣性。すべてのプラットフォームで、スクロールと休止がそのスタイルで行われるため、スクロールと休止のスタイルが不自然になることはありません。

クロスブラウザの互換性

テストは、Opera、Firefox、Safari、Chrome、Android、iOS で実施されました。機能とサポートに違いがあるウェブ機能の概要は次のとおりです。

ただし、一部の CSS は適用されなかったため、現在、一部のプラットフォームでは UX の最適化が行われていません。これらの機能を管理する必要がないのは便利でした。最終的には他のブラウザやプラットフォームにも展開されると思います。

scroll-snap-stop

カルーセルは、CSS スクロール スナップ ポイントの仕様を作成した主な UX ユースケースの 1 つです。ストーリーとは異なり、カルーセルでは、ユーザーが操作した後に各画像で停止する必要はありません。カルーセルをすばやく切り替えても問題ない、または切り替えることを推奨する場合もあります。一方、ストーリーは 1 つずつ移動するのが最適です。これはまさに scroll-snap-stop が提供するものです。

.user {
  scroll-snap-align: start;
  scroll-snap-stop: always;
}

この記事の執筆時点では、scroll-snap-stop は Chromium ベースのブラウザでのみサポートされています。更新については、ブラウザの互換性をご覧ください。ただし、ブロック要素ではありません。サポートされていないブラウザでは、ユーザーが誤って友達をスキップする可能性があることを意味します。そのため、ユーザーはより慎重に操作する必要があります。または、スキップした友だちが視聴済みとしてマークされないように JavaScript を記述する必要があります。

詳しくは、仕様をご覧ください。

overscroll-behavior

モーダルの背後にあるコンテンツを突然スクロールし始めたら、モーダルをスクロールしたことがありますか。overscroll-behavior を使用すると、デベロッパーはスクロールを捕捉し、そのまま放置することができます。さまざまなシーンで活躍します。マイストーリー コンポーネントでは、この機能を使用して、スワイプやスクロールの追加操作でコンポーネントから離れないようにします。

.stories {
  overflow-x: auto;
  overscroll-behavior: contain;
}

Safari と Opera の 2 つのブラウザはこれをサポートしていませんでしたが、これは問題ありません。これらのユーザーには、これまでどおりのオーバースクロール エクスペリエンスが提供されるため、この機能強化に気付かない可能性があります。私は個人的にこの機能の大ファンで、実装するオーバースクロール機能のほぼすべてにこの機能を含めています。無害な追加であり、UX の向上につながるだけです。

scrollIntoView({behavior: 'smooth'})

ユーザーがタップまたはクリックを行い、友だちの一連の記事の最後に達したら、スクロール スナップ ポイント セットの次の友だちに移動します。JavaScript を使用すると、次の友だちを参照し、スクロールして表示するようリクエストできます。基本的なサポートは優れています。すべてのブラウザでスクロールして表示されました。しかし、すべてのブラウザが 'smooth' したわけではありません。これは、スナップではなくスクロールして表示されたことを意味します。

element.scrollIntoView({
  behavior: 'smooth'
})

Safari は、ここで behavior: 'smooth' をサポートしていない唯一のブラウザでした。最新情報については、ブラウザの互換性をご覧ください。

ハンズオン

私の方法をご覧になったところで、あなたならどうしますか?アプローチを多様化し、ウェブで構築するすべての方法を学びましょう。Glitch を作成して、自分のバージョンをツイートしてください。下記のコミュニティのリミックス セクションに追加します。

コミュニティ リミックス