テレビ、スマートフォン、パソコンなどのレスポンシブな横向きスクロールビューを作成する方法の基本的な概要。
この記事では、最小限でレスポンシブかつアクセスしやすい、ブラウザやプラットフォーム(テレビなど)をまたいで動作する、ウェブの横方向スクロール エクスペリエンスを作成する方法について考えたいと思います。デモをお試しください。
動画で確認したい場合は、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 Steiner の https://web.dev/color-scheme/ をご覧ください。
コンテンツを追加
ul > li > a > figure > picture > img
のコンテンツ構造が決まったら、次はスクロールして表示する画像とタイトルを追加します。このデモには静的なプレースホルダの画像とテキストが含まれていますが、お好きなデータソースからデータを取得して使用できます。
CSS でスタイルを追加する
次に、CSS を使用して、この汎用的なコンテンツ リストをエクスペリエンスに変換します。Netflix、アプリストアなど、多くのサイトやアプリでは、水平方向のスクロール領域を使用して、カテゴリとオプションをビューポートに詰め込んでいます。
スクロール レイアウトを作成する
レイアウトでコンテンツが途切れたり、省略記号でテキストが切り捨てられたりしないようにすることが重要です。多くのテレビには、このようなものと同じメディア スクロール機能がありますが、コンテンツを省略することがよくあります。このレイアウトはそうではありません。また、メディア コンテンツで列サイズをオーバーライドできるため、1 つのレイアウトでさまざまな組み合わせを柔軟に処理できます。
コンテナでは、デフォルトのサイズをカスタム プロパティとして指定することで、列サイズをオーバーライドできます。このグリッド レイアウトは列サイズに固有のものであり、間隔と方向のみを管理します。
.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 回に 1 つのフォーカス可能なアイテムを操作するこのエクスペリエンスは、タブキーを 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 ブラウザまたはセットトップ ボックスでは利用できます。メディア スクロール グリッド レイアウトでは方向と間隔のみを指定するため、アスペクト比のサポートを確認するメディアクエリ内でサイズが変更される可能性があります。より動的でスクロール可能なメディア スクロールへの段階的な拡張。
@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 でページの読み込み時間とデータ使用量を大幅に削減する方法について説明します。レベル 5 の prefers-reduced-data
メディア クエリを使用すると、デバイスがデータセーバー モードなどのデータ使用量を抑えた状態にあるかどうかを問い合わせることができます。お客様のアカウントが管理者権限をお持ちの場合は、ドキュメントを変更して、この場合は画像を非表示にすることができます。
figure {
@media (prefers-reduced-data: reduce) {
& {
min-inline-size: var(--size);
& > picture {
display: none;
}
}
}
}
コンテンツは引き続き操作できますが、サイズの大きい画像をダウンロードする費用はかかりません。prefers-reduced-data
CSS を追加する前のサイトは次のとおりです。
(7 件のリクエスト、131 ミリ秒で 100 KB のリソース)
prefers-reduced-data
CSS を追加した後のサイトのパフォーマンスは次のとおりです。
(71 件のリクエスト、1.07 秒で 1.2 MB のリソース)
リクエストが 64 件減りました。これは、このブラウザタブのビューポート内の画像(ワイドスクリーン ディスプレイでテスト)が約 60 枚減ったことを意味します。ページ読み込みが約 80% 高速化され、ワイヤーを介したデータが 10% 削減されました。かなり強力な CSS です。
まとめ
私の方法をご覧になったところで、あなたならどうしますか?🙂
アプローチを多様化し、ウェブで構築するすべての方法を学びましょう。Codepen を作成するか、独自のデモをホストして、そのデモをツイートしてください。デモを以下のコミュニティ リミックスのセクションに追加します。
ソース
コミュニティ リミックス
表示する項目はありません