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

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

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

デモ

この Stories コンポーネントを自分で作成するデモを実際に試したい場合は、Stories コンポーネントの Codelab をご覧ください。

動画でご覧になりたい場合は、こちらの YouTube 版をご覧ください。

概要

ストーリーの UX の一般的な例としては、Snapchat ストーリーや Instagram ストーリー(フリートも含む)があります。一般的な UX の用語では、ストーリーは通常、複数のサブスクリプションをナビゲートするためのモバイル専用のタップ中心のパターンです。たとえば、Instagram でユーザーが友だちのストーリーを開き、その中の写真を見ていく場合などです。通常、一度に多くの友だちを削除します。デバイスの右側をタップすると、その友だちの次のストーリーにスキップします。右にスワイプすると、別の友だちにスキップします。ストーリー コンポーネントはカルーセルとよく似ていますが、1 次元配列ではなく多次元配列をナビゲートできます。各カルーセルの中にカルーセルがあるような状態です。🤯

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

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

全体として、このコンポーネントはいくつかの重要なウェブ プラットフォーム機能のおかげで、かなり簡単に構築できました。それらについて説明します。

CSS グリッド

CSS Grid にはコンテンツを操作する強力な方法がいくつか備わっているため、このレイアウトは 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 によって作成された列をハイライト表示する

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

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

モバイルでは、行のサイズがビューポートの高さ、各列がビューポートの幅に相当します。Snapchat ストーリーズと Instagram ストーリーズの例を続けると、各列は友人のストーリーズになります。友だちのストーリーがビューポートの外に続くようにして、スクロールできるようにします。Grid は、各友だちのストーリーの HTML をレイアウトするために必要な数の列を作成し、動的でレスポンシブなスクロール コンテナを作成します。Grid を使用することで、効果全体を一元化できました。

スタッキング

各友だちのストーリーは、ページネーションに対応した状態にする必要があります。アニメーションなどの楽しいパターンを準備するために、スタックを選択しました。スタックとは、横からではなく、サンドイッチを上から見たような状態を指します。

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 氏の Introducing CSS Scroll Snap Points をご覧ください。

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;
}
子どもがスナップの対象になることを選択します。

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

  • アクセシビリティ機能は無料。Scroll Snap Points の仕様では、左矢印キーと右矢印キーを押すと、デフォルトでスナップ ポイントを移動すると規定されています。
  • 仕様の拡大。スクロール スナップ ポイントの仕様は常に新機能と改善が加えられているため、私の Stories コンポーネントは今後も改善されていくでしょう。
  • 実装の容易さ。スクロール スナップ ポイントは、タッチ操作を中心とした水平ページネーションのユースケース向けに実質的に構築されています。
  • プラットフォーム スタイルの自由な慣性。すべてのプラットフォームで、正規化された慣性とは異なり、不気味なスクロールや停止のスタイルになることはありません。

クロスブラウザの互換性

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 を使用すると、デベロッパーはスクロールをトラップして、スクロールが離れないようにすることができます。さまざまな場面で活躍します。My Stories コンポーネントは、追加のスワイプやスクロール ジェスチャーがコンポーネントから離れるのを防ぐために使用します。

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

Safari と Opera はこの機能をサポートしていませんが、まったく問題ありません。これらのユーザーは、これまでと同じようにオーバースクロールを体験できるため、この機能強化に気づかない可能性があります。私は個人的にこの機能が大好きで、実装するほぼすべてのオーバースクロール機能にこの機能を含めています。UX の向上につながるだけで、害はありません。

scrollIntoView({behavior: 'smooth'})

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

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

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

ハンズオン

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

コミュニティ リミックス