CSS
:root {
--hint-w: 44px;
--hint-bg: rgba(255,255,255,0.95);
--hint-fg: #333;
}
body { font-family: system-ui, sans-serif; margin: 24px; }
.scroll-area {
position: relative;
max-inline-size: 560px; /* デモ用。不要なら削除OK */
border: 1px solid #ddd;
border-radius: 8px;
background: #fff;
/* 兄弟 (.right-hint) から --x タイムラインを参照できるように */
timeline-scope: --x;
}
/* ====== 要素内の横スクロールを確実に起こす構造 ====== */
.scroller {
overflow-x: auto; /* ご要望の overflow-x:auto */
overflow-y: hidden;
display: block; /* ビューポート化(幅固定) */
inline-size: 100%;
padding: 12px;
box-sizing: border-box;
scroll-behavior: smooth;
overscroll-behavior-x: contain;
/* スクロール進捗タイムライン(横方向) */
scroll-timeline-name: --x;
scroll-timeline-axis: inline;
}
.track {
display: inline-flex;
gap: 12px;
/* 中身の合計幅に合わせて広がる=scroller幅を超えやすくする */
min-inline-size: max-content;
}
.card {
inline-size: 200px;
block-size: 100px;
border-radius: 8px;
border: 1px solid #e5e5e5;
background: #fafafa;
padding: 12px;
box-sizing: border-box;
flex: 0 0 auto;
}
/* 右端の矢印ヒント(フォールバックでは非表示のまま) */
.right-hint {
position: absolute;
inset-block: 0;
inset-inline-end: 0; /* 右端 */
inline-size: var(--hint-w);
display: flex;
align-items: center;
justify-content: center;
pointer-events: none;
color: var(--hint-fg);
background: linear-gradient(to left, var(--hint-bg) 45%, rgba(255,255,255,0));
border-radius: 8px;
opacity: 0; /* タイムライン未対応 or 非スクロール時は非表示 */
}
.right-hint::before {
content: "➔"; /* お好みで "→" など */
font-size: 20px;
line-height: 1;
animation: nudge 1.6s ease-in-out infinite;
}
@keyframes nudge {
0%, 100% { transform: translateX(2px); opacity: .9; }
50% { transform: translateX(6px); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
.right-hint::before { animation: none; }
}
/* ===== Scroll-Driven Animations に対応している場合だけ有効化 ===== */
@supports (animation-timeline: scroll()) or (scroll-timeline-name: --dummy) {
.right-hint {
/* スクロール進捗に同期して可視状態→不可視へ */
animation-name: fadeRightHint;
animation-timeline: --x; /* .scroller のスクロール進捗 */
/* 0%〜96%の間は 0% キーフレーム(=表示)を維持し、
96%→100% で 1 まで進んでフェードアウト。
範囲外は fill:both で端の状態を保持。 */
animation-range: 0% 96%;
animation-duration: 1ms; /* 時間値はダミー(タイムライン駆動) */
animation-timing-function: linear;
animation-fill-mode: both;
}
@keyframes fadeRightHint {
0% { opacity: 1; } /* まだ右に余地あり → 表示 */
100% { opacity: 0; } /* 末尾付近〜末尾 → 消える */
}
}