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

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

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

デモ

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

動画で確認したい場合は、YouTube 版の投稿をご覧ください。

概要

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

カードを使用して可視化された多次元配列。左から右に紫色の枠線のカードが積み重ねられており、各カードの中には青色の枠線のカードが 1 枚以上あります。リスト内のリスト。
1 つ目のカルーセル(フレンド)
2 つ目のカルーセル(ストーリー)
👍? リスト内のリスト(多次元配列)

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

全体的に、いくつかの重要なウェブ プラットフォーム機能のおかげで、このコンポーネントは非常に簡単に構築できました。詳しく見てみましょう。

CSS グリッド

コンテンツを整理する強力な方法が用意されているため、CSS グリッドでこのレイアウトを実現するのは難しくありませんでした。

フレンドのレイアウト

主な .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 による 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 を作成して、自分のバージョンをツイートしてください。下記のコミュニティのリミックス セクションに追加します。

コミュニティ リミックス