1. 質問と背景
コンテンツページの上部に読了プログレスバーを配置し、カードがスクロールコンテナに入るときにフェードインさせる必要があります。チームは最初、スクロールイベントリスナーとrequestAnimationFrameを使用しましたが、ローエンドデバイスでメインスレッドのカクつき(jank)が発生しました。CSSスクロールドリブンアニメーション(CSS Scroll-driven Animations)を使用して再設計し、スクロール進行状況(scroll progress)とビュー進行状況(view progress)の違いを説明し、非対応ブラウザ、視覚効果の抑制(reduced motion)、検証方法をカバーしてください。
2. 面接官が評価するポイント
- CSSアニメーションが、デフォルトの時間ベースのタイムラインの代わりにスクロールタイムラインまたはビュータイムラインに従うことができると理解しているか。
- スクロールコンテナの位置を追跡するscroll()と、最も近いスクロールコンテナ内の要素の表示範囲を追跡するview()を区別できているか。
- 名前付きタイムライン、アニメーション範囲、overflowの前提条件、およびショートハンドのリセット順序を適切に扱えるか。
- 互換性、パフォーマンス、キーボード操作による閲覧、reduced motion、JavaScriptなしのフォールバックが設計に含まれているか。
3. 回答前に確認すべき明確化の質問
- プログレスバーはドキュメント全体に従うべきですか、それとも内部の記事スクローラーに従うべきですか?
- カードのアニメーションは表示時に1回だけ実行するべきですか、それとも可視割合に応じて前後に連動して動くべきですか?
- どのブラウザのサポートが必須であり、どのような視覚的・機能的フォールバックが許容されますか?
- 視覚効果の抑制を好むユーザーにもプログレスの変化を見せるべきですか?また、モーションが読み上げ順序やフォーカスに影響を与える可能性はありますか?
4. 30秒の回答フレームワーク
読了バーをスクローラーのスクロール進行状況タイムラインにバインドし、カードをビュー進行状況タイムラインにバインドします。scroll()はスクローラーの開始位置から終了位置までの進行状況を表し、view()は最も近いスクローラーの可視範囲への要素の出入りを表します。キーフレームが視覚的な変化を定義し、animation-timelineが進行状況を提供します。コンテナには実際のスクロール可能距離が必要であり、アニメーション範囲は明示的でなければなりません。非対応ブラウザでは静的なプログレス表示を維持するか、スロットル処理された軽量なJavaScriptフォールバックを使用し、コアコンテンツがモーションに依存しないようにします。supportsチェック、reduced-motionの挙動、キーボードテスト、ローエンドデバイスでの測定を追加します。
5. ステップごとの詳細な回答
ステップ 1: タイムラインのセマンティクスを確立する
スクロール進行状況タイムライン(scroll progress timeline)はスクローラーの位置によって駆動され、通常は開始時の0%から終了時の100%まで動きます。ビュー進行状況タイムライン(view progress timeline)は、最も近いスクローラーに対するターゲット要素の可視範囲によって駆動され、ビューポートに入退場するカードに適しています。どちらもCSS AnimationsおよびWeb Animations APIのタイムラインモデルをベースに構築されています。
ステップ 2: 読了プログレスバーを実装する
記事コンテナが実際にオーバーフローするように設定し、そのスクロールタイムラインに名前を付け、プログレス要素のanimation-timelineをその名前に向けます。キーフレームなしでanimation-timelineを設定してはならず、スクロール範囲のないコンテナを使用可能なタイムラインとして扱ってはいけません。
.article-scroller {
overflow-y: auto;
scroll-timeline-name: --article-scroll;
scroll-timeline-axis: block;
}
.reading-progress {
transform-origin: left center;
animation: grow-progress linear;
animation-timeline: --article-scroll;
}
@keyframes grow-progress {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}ステップ 3: カード用のビュータイムラインを実装する
カードは、最も近い祖先スクローラーにおける可視性を追跡する匿名view()タイムラインを使用できます。より厳密に制御するには、view-timeline-nameで名前を付け、view-timeline-insetで開始境界と終了境界を調整します。カードが端に触れた瞬間にアニメーション全体が終了してしまわないよう、範囲は意図した表示ゾーンに一致させる必要があります。
.card {
animation: reveal-card linear both;
animation-timeline: view(block 15% 15%);
}
@keyframes reveal-card {
entry 0% { opacity: 0; transform: translateY(1rem); }
cover 45% { opacity: 1; transform: translateY(0); }
exit 100% { opacity: 0.6; }
}ステップ 4: 範囲とショートハンドの罠に対処する
名前付きタイムラインおよび匿名タイムラインには、正しいスクローラー関係が必要です。overflow、軸(axis)、または要素の階層関係に不整合があると、タイムラインに進行状況が発生しなくなります。animationショートハンドは省略されたタイムラインコンポーネントをデフォルト値にリセットするため、animation-timelineはショートハンドの後に宣言してください。明示的なentry、cover、exitフェーズにはanimation-rangeまたは範囲キーフレームを使用し、ターゲットブラウザでテストします。
ステップ 5: フォールバックとアクセシビリティの検証を設計する
@supportsを使用してanimation-timelineを検出します。機能拡張が利用できない場合は、静的なプログレス表示、通常の読み取り順序、可読性のあるコントラストを維持します。動的なフォールバックが必要な場合は、スクロール処理をスロットルし、繰り返しのレイアウト計算を避けます。prefers-reduced-motion: reduce環境では、プログレス情報とフォーカス順序を保持したまま、移動(translation)や継続的なモーションを削除します。キーボードスクロール、スクリーンリーダー、高速な逆スクロール、ネストされたスクローラー、およびローエンドデバイスでのフレーム時間をテストします。
6. 高品質な回答サンプル
読了バーを記事スクローラーのスクロール進行状況タイムラインにバインドし、カードを最も近いスクローラー内のビュー進行状況タイムラインにバインドします。前者は0%から100%までのスクロール位置を表し、後者は要素が可視範囲に入り、覆い、出ることを表します。実際のオーバーフローを確認した上で、ショートハンドによるタイムラインのリセットを防ぐ順序でキーフレームとanimation-timelineを定義します。@supportsで静的なフォールバックを提供し、必要な場合のみスロットルされたJavaScriptを使用します。reduced-motionでは、コンテンツ、プログレス、フォーカスを保持しながら、移動や継続的な効果を削除します。キーボード操作、スクリーンリーダー、ネストされたスクロール、ローエンド環境でのフレーム時間を検証します。
7. よくある間違い
- scroll()とview()を同じ進行状況として扱う → カードが表示状態に追従しない → まずスクローラー位置と要素の可視性の違いを説明する。
- オーバーフローしないコンテナにスクロールタイムラインを宣言する → アニメーションが進行しない → コンテンツサイズ、overflow、軸を確認する。
- animationショートハンドによってanimation-timelineが上書きされる → デフォルトタイムラインに戻ってしまう → ショートハンドの後に再度animation-timelineを宣言する。
- モダンブラウザでのみコンテンツを表示する → 古いブラウザでコア機能が失われる → 静的な表示と通常の読み取り順序を維持する。
- reduced motionに対してopacityのみをゼロにする → フィードバックが消える → セマンティックな状態と可視状態を維持したまま、移動や継続的なモーションを削除する。
8. フォローアップ質問と回答
フォローアップ 1: スクロールタイムラインとビュータイムラインはいつ使い分けますか?
スクロール領域全体にわたる進行状況にはスクロールタイムラインを使用します。スクローラーに入退場・通過する要素にはビュータイムラインを使用します。決定要素はJavaScriptの有無ではなく、進行状況のソース(発生元)です。
フォローアップ 2: animation-timelineを宣言したのにアニメーションが動作しない原因は何ですか?
一般的な原因は、実際のスクロール範囲の欠如、軸の不一致、祖先関係の範囲外にあるタイムライン名、または後続のanimationショートハンドによるタイムラインのリセットです。overflow、タイムラインの関係、宣言順序をこの順序で確認します。
フォローアップ 3: 古いブラウザ向けにはどのようにデグレードさせますか?
静的なプログレス表示と完全なコンテンツを維持します。動的なプログレスが不可欠な場合は、わずかな更新のためにスロットルされたスクロールリスナーを使用します。フォールバックによって読み取り順序、キーボードアクセス、フォーカスの挙動が変更されてはなりません。
フォローアップ 4: 視覚効果の抑制(reduced motion)にはどのように配慮しますか?
prefers-reduced-motion: reduceのもとでは、移動(translation)、拡大縮小、長時間続くモーションを削除します。静的または即時のプログレス更新、コンテンツ順序、読みやすいフィードバックを維持し、高速スクロールによって情報が隠れてしまわないことを検証します。