メディア スクローラー コンポーネントの作成

テレビ、スマートフォン、パソコンなどのレスポンシブな横向きスクロールビューを作成する方法の基本的な概要

この投稿では、最小限のレスポンシブで、アクセスしやすく、ブラウザやプラットフォーム(テレビなど)をまたいで機能するウェブの水平スクロール エクスペリエンスを作成する方法についての考え方を共有します。デモをお試しください。

デモ

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

概要

メディアや商品のサムネイルをホストするための横方向のスクロール レイアウトを作成します。このコンポーネントは、単純な <ul> リストとして始まりますが、CSS によって、画像を表示し、グリッドにスナップする、満足のいくスムーズなスクロール エクスペリエンスに変換されます。ロービング インデックスの操作を容易にする JavaScript が追加され、キーボード ユーザーは 100 以上のアイテムの移動をスキップできるようになります。また、試験運用版のメディアクエリ prefers-reduced-data を使用して、メディア スクロールを軽量なタイトル スクロールに変換できます。

ユーザー補助対応のマークアップから始める

メディア スクロールは、アイテムを含むリストという、ほんの数個のコア コンポーネントで構成されています。リストは、最もシンプルな形で世界中に配信され、誰もが明確に利用できます。このページにアクセスしたユーザーは、リストをブラウジングし、リンクをクリックしてアイテムを表示できます。これがアクセス可能なベースです。

<ul> 要素を含むリストを配信します。

<ul class="horizontal-media-scroller">
  <li></li>
  <li></li>
  <li></li>
  ...
<ul>

<a> 要素を使用してリストアイテムをインタラクティブにします。

<li>
  <a href="#">
    ...
  </a>
</li>

<figure> 要素を使用して、画像とそのキャプションをセマンティックに表します。

<figure>
  <picture>
    <img alt="..." loading="lazy" src="https://picsum.photos/500/500?1">
  </picture>
  <figcaption>Legends</figcaption>
</figure>

<img>alt 属性と loading 属性に注意してください。メディア スクロールの代替テキストは、サムネイルに追加のコンテキストを提供したり、画像が読み込まれなかった場合にフォールバック テキストとして使用したり、スクリーン リーダーなどの支援技術に依存するユーザーに音声 UI を提供したりできるUX の機会です。詳しくは、コンプライアンスを遵守した代替テキストの 5 つの黄金律をご覧ください。

loading 属性にキーワード lazy を指定すると、画像がビューポート内にある場合にのみこの画像ソースを取得する必要があることを示します。ユーザーは、スクロールして表示したアイテムの画像しかダウンロードしないため、大規模なリストでは非常に便利です。

ユーザーが希望するカラーパターンをサポートする

color-scheme<meta> タグとして使用して、ページで提供されるライトモードとダークモードの両方のユーザー エージェント スタイルが必要なことをブラウザに通知します。見方に応じて、無料のダークモードまたはライトモードです。

<meta name="color-scheme" content="dark light">

メタタグは可能な限り早い段階でシグナルを提供するため、ユーザーがダークモードを設定している場合は、ブラウザが暗いデフォルトのキャンバス色を選択できます。つまり、サイト内のページ間を移動する際に、読み込みの合間に白いキャンバスの背景が点滅することはありません。読み込み間でのダークモードのシームレスな切り替えにより、目への負担が軽減されます。

詳しくは、Thomas Steinerhttps://web.dev/color-scheme/ をご覧ください。

コンテンツを追加

ul > li > a > figure > picture > img のコンテンツ構造が決まったら、次はスクロールして表示する画像とタイトルを追加します。このデモには静的なプレースホルダの画像とテキストが含まれていますが、お好きなデータソースからデータを取得して使用できます。

CSS でスタイルを追加する

次に、CSS を使用して、この汎用的なコンテンツ リストをエクスペリエンスに変換します。Netflix やアプリストアをはじめ、多くのサイトやアプリでは、水平スクロール領域を使用してビューポートにカテゴリやオプションを詰め込みます。

スクロール レイアウトを作成する

レイアウトでコンテンツが途切れることや、省略記号を使用してテキストが切り捨てられないようにすることが重要です。多くのテレビには、このようなものと同じメディア スクロール機能がありますが、コンテンツを省略することがよくあります。このレイアウトはそうではありません。また、メディア コンテンツで列サイズをオーバーライドできるため、1 つのレイアウトでさまざまな組み合わせを柔軟に処理できます。

スクロール可能な 2 行が表示されています。一方は省略記号がないため、高さが高く、各タイトルが完全に判読できます。もう一つは短く、多くのタイトルが省略記号で切り捨てられています。

このコンテナでは、デフォルトのサイズをカスタム プロパティとして指定することで、列のサイズをオーバーライドできます。このグリッド レイアウトは列サイズに固有のものであり、間隔と方向のみを管理します。

.horizontal-media-scroller {
  --size: 150px;

  display: grid;
  grid-auto-flow: column;
  gap: calc(var(--gap) / 2); /* parent owned value for children to be relative to*/
  margin: 0;
}

カスタム プロパティは、<picture> 要素によってベースのアスペクト比(ボックス)を作成するために使用されます。

.horizontal-media-scroller {
  --size: 150px;

  display: grid;
  grid-auto-flow: column;
  gap: calc(var(--gap) / 2);
  margin: 0;

  & picture {
    inline-size: var(--size);
    block-size: var(--size);
  }
}

いくつかのマイナーなスタイルを追加して、メディア スクロールの基本を完成させます。

.horizontal-media-scroller {
  --size: 150px;

  display: grid;
  grid-auto-flow: column;
  gap: calc(var(--gap) / 2);
  margin: 0;

  overflow-x: auto;
  overscroll-behavior-inline: contain;

  & > li {
    display: inline-block; /* removes the list-item bullet */
  }

  & picture {
    inline-size: var(--size);
    block-size: var(--size);
  }
}

overflow を設定すると、リスト内のスクロールとキーボード ナビゲーションを許可するように <ul> が設定されます。その後、各直接子 <li> 要素の ::marker が削除され、新しい表示タイプ inline-block が取得されます。

ただし、画像はまだレスポンシブではなく、入っている箱から飛び出します。いくつかのサイズ、フィット感、枠線のスタイル、遅延読み込み時の背景のグラデーションなどを設定します。

img {
  /* smash into whatever box it's in */
  inline-size: 100%;
  block-size: 100%;

  /* don't squish but do cover the space */
  object-fit: cover;

  /* soften the edges */
  border-radius: 1ex;
  overflow: hidden;

  /* if empty, show a gradient placeholder */
  background-image:
    linear-gradient(
      to bottom,
      hsl(0 0% 40%),
      hsl(0 0% 20%)
    );
}

スクロール パディング

ページ コンテンツとの位置合わせと、端から端までスクロールできるサーフェス領域は、調和のとれたミニマルなコンポーネントに不可欠です。

タイポグラフィとレイアウトの線に合わせて端から端までスクロールするレイアウトを実現するには、scroll-padding と一致する padding を使用します。

.horizontal-media-scroller {
  --size: 150px;

  display: grid;
  grid-auto-flow: column;
  gap: calc(var(--gap) / 2);
  margin: 0;

  overflow-x: auto;
  overscroll-behavior-inline: contain;

  padding-inline: var(--gap);
  scroll-padding-inline: var(--gap);
  padding-block: calc(var(--gap) / 2); /* make space for scrollbar and focus outline */
}

水平方向のスクロール パディングのバグ修正上記は、スクロール コンテナを簡単にパディングできることを示しています。ただし、互換性に関する問題が未解決です(Chromium 91 以降では修正されています)。詳しくはこちらをご覧ください。簡単に説明すると、スクロールビューでパディングが考慮されないことがよくありました。

最後のリストアイテムの行内端側にボックスがハイライト表示されています。これは、必要な配置を作成するために、パディングと要素の幅が同じであることを示しています。

ブラウザにスクロールバーの末尾にパディングを配置させるようにするため、各リストの最後の数字をターゲットにし、必要なパディング量の疑似要素を追加します。

.horizontal-media-scroller > li:last-of-type figure {
  position: relative;

  &::after {
    content: "";
    position: absolute;

    inline-size: var(--gap);
    block-size: 100%;

    inset-block-start: 0;
    inset-inline-end: calc(var(--gap) * -1);
  }
}

論理プロパティを使用すると、メディア スクロールを任意の書き込みモードとドキュメントの向きで動作させることができます。

スクロールのスナップ

オーバーフローのスクロール コンテナは、1 行の CSS でスナップ ビューポートにできます。そのビューポートにどのように配置するかは、子に任されます。

.horizontal-media-scroller {
  --size: 150px;

  display: grid;
  grid-auto-flow: column;
  gap: calc(var(--gap) / 2);
  margin: 0;

  overflow-x: auto;
  overscroll-behavior-inline: contain;

  padding-inline: var(--gap);
  scroll-padding-inline: var(--gap);
  padding-block-end: calc(var(--gap) / 2);

  scroll-snap-type: inline mandatory;

  & figure {
    scroll-snap-align: start;
  }
}

フォーカス

このコンポーネントは、テレビやアプリストアなどでの人気から着想を得ています。多くのビデオゲーム プラットフォームでは、メインのホーム画面レイアウトとして、このスクローラーによく似たメディア スクローラーを使用します。フォーカスは、単なる追加機能ではなく、大きな UX 要素です。リモコンを使ってソファからこのメディア スクロールを使用するとしましょう。その操作を少し改善してみましょう。

.horizontal-media-scroller a {
  outline-offset: 12px;

  &:focus {
    outline-offset: 7px;
  }

  @media (prefers-reduced-motion: no-preference) {
    & {
      transition: outline-offset .25s ease;
    }
  }
}

これにより、フォーカスの輪郭スタイル 7px がボックスから離れ、適度なスペースが確保されます。ユーザーがモーションの軽減に関するモーション設定を行っていない場合、オフセットが遷移され、フォーカス イベントに微妙なモーションを与えます。

ロービング インデックス

ゲームパッドやキーボードのユーザーは、スクロールするコンテンツとオプションが長いリストで特に注意する必要があります。この問題を解決するための一般的なパターンは、ロービング インデックスと呼ばれます。アイテムのコンテナがキーボード フォーカスされているが、一度にフォーカスを保持できるのは 1 つのみの場合です。一度に 1 つのフォーカス可能なアイテムを表示するエクスペリエンスは、Tab を 50 回以上押して終了に移動するのではなく、長い可能性のあるアイテムリストを回避できるように設計されています。

デモの最初のスクロールには 300 個のアイテムがあります。すべてを走査させて次のセクションに進むこともできます

このエクスペリエンスを作成するには、JavaScript でキーボード イベントとフォーカス イベントを監視する必要があります。このユーザー エクスペリエンスを簡単に実現できるように、npm に小さなオープンソース ライブラリを作成しました。3 つのスクロールバーで使用方法は次のとおりです。

import {rovingIndex} from 'roving-ux';

rovingIndex({
  element: someElement
});

このデモでは、ドキュメントに対してスクローラーのクエリを実行し、スクローラーごとに rovingIndex() 関数を呼び出します。rovingIndex() に要素を渡すことで、フォーカス ターゲットが直接の子孫でない場合に、リストコンテナなどの移動エクスペリエンスと、ターゲット クエリ セレクタを取得します。

document.querySelectorAll('.horizontal-media-scroller')
  .forEach(scroller =>
    rovingIndex({
      element: scroller,
      target: 'a',
}))

この効果の詳細については、オープンソース ライブラリ roving-ux をご覧ください。

アスペクト比

この記事の執筆時点では、aspect-ratio のサポートは Firefox ではフラグが設定されていますが、Chromium ブラウザまたはセットトップ ボックスでは利用できます。メディア スクロール グリッド レイアウトでは方向と間隔のみを指定するため、アスペクト比のサポートを確認するメディアクエリ内でサイズが変更される可能性があります。より動的でスクロール可能なメディア スクロール機能への段階的な拡張。

16:9 と 4:3 の他のデザイン比率の横に、4:4 のアスペクト比のボックスが表示されます。

@supports (aspect-ratio: 1) {
  .horizontal-media-scroller figure > picture {
    inline-size: auto; /* for a block-size driven ratio */
    aspect-ratio: 1; /* boxes by default */

    @nest section:nth-child(2) & {
      aspect-ratio: 16/9;
    }

    @nest section:nth-child(3) & {
      /* double the size of the others */
      block-size: calc(var(--size) * 2);
      aspect-ratio: 4/3;

      /* adjust size to fit more items into the viewport */
      @media (width <= 480px) {
        block-size: calc(var(--size) * 1.5);
      }
    }
  }
}

ブラウザが aspect-ratio 構文をサポートしている場合、メディア スクローラーの画像は aspect-ratio サイズにアップグレードされます。下書きのネスト構文を使用すると、各画像のアスペクト比は、1 行目、2 行目、3 行目かによって変わります。ネスト構文を使用すると、他のサイズ変更ロジックとともに、ビューポートの微調整を設定することもできます。

この CSS では、この機能をより多くのブラウザ エンジンで利用できるようになるため、管理しやすく、より視覚に訴えるレイアウトがレンダリングされます。

データの削減を優先する

次の手法は Canaryフラグありの場合にのみ使用できますが、数行の CSS でページの読み込み時間とデータ使用量を大幅に削減する方法について説明します。レベル 5prefers-reduced-data メディア クエリを使用すると、デバイスがデータセーバー モードなどのデータ使用量を抑えた状態にあるかどうかを問い合わせることができます。お客様のアカウントが管理者権限をお持ちの場合は、ドキュメントを変更して、この場合は画像を非表示にすることができます。

ALT_TEXT_HERE

figure {
  @media (prefers-reduced-data: reduce) {
    & {
      min-inline-size: var(--size);

      & > picture {
        display: none;
      }
    }
  }
}

コンテンツは引き続き操作できますが、サイズの大きい画像をダウンロードする費用はかかりません。prefers-reduced-data CSS を追加する前のサイトは次のとおりです。

(7 件のリクエスト、100 KB のリソース、131 ミリ秒で処理)

ALT_TEXT_HERE

CSS 「prefers-reduced-data」を追加した後のサイトのパフォーマンスは次のようになります。

ALT_TEXT_HERE

(71 件のリクエスト、1.07 秒で 1.2 MB のリソース)

リクエストが 64 件減りました。これは、このブラウザタブのビューポート内の画像(ワイドスクリーン ディスプレイでテスト)が約 60 枚減ったことを意味します。ページ読み込みが約 80% 高速化され、ワイヤーを介したデータが 10% 削減されました。かなり強力な CSS です。

まとめ

私の方法をご覧になったところで、あなたならどうしますか?🙂

アプローチを多様化し、ウェブで構築するすべての方法を学びましょう。Codepen を作成するか、独自のデモをホストして、そのデモをツイートしてください。デモを以下のコミュニティ リミックスのセクションに追加します。

ソース

コミュニティ リミックス

表示する項目はありません