HextaUI

Scroll fade

スクロール領域の端。さらに見るものがあるときだけフェードし、スクロール位置のみを使って CSS だけで駆動されます。

  • v2.24.0Released
  • v2.23.0Released
  • v2.22.0Released
  • v2.21.0Released
  • v2.20.0Released
  • v2.19.0Released
  • v2.18.0Released
  • v2.17.0Released
  • v2.16.0Released
  • v2.15.0Released
  • v2.14.0Released
  • v2.13.0Released
  • v2.12.0Released
  • v2.11.0Released
  • v2.10.0Released
  • v2.9.0Released
  • v2.8.0Released
  • v2.7.0Released
  • v2.6.0Released
  • v2.5.0Released
  • v2.4.0Released
  • v2.3.0Released
  • v2.2.0Released
  • v2.1.0Released
const releases = Array.from({ length: 24 }, (_, index) => `v2.${24 - index}.0`)

export function ScrollFadeDemo() {
  return (
    <div className="w-full max-w-xs rounded-xl bg-muted">
      <ul
        tabIndex={0}
        aria-label="Releases"
        className="h-64 scroll-fade overflow-y-auto rounded-xl p-2 text-sm outline-none focus-visible:ring-3 focus-visible:ring-focus-ring focus-visible:outline-hidden"
      >
        {releases.map((release) => (
          <li
            key={release}
            className="flex h-9 items-center justify-between rounded-md px-3"
          >
            <span className="font-mono">{release}</span>
            <span className="text-muted-foreground">Released</span>
          </li>
        ))}
      </ul>
    </div>
  )
}

scroll fade は、shadcn の tailwind.css に含まれる Tailwind ユーティリティ群です。HextaUI のテーマがすでにインポートしているため、テーマや任意のコンポーネントを追加済みであれば使えます。

pnpm dlx shadcn@latest add https://hextaui.com/r/theme.json

テーマを使わない場合は、shadcn をインストールし、Tailwind の後にその CSS をインポートしてください。

pnpm add shadcn
app/globals.css
@import "tailwindcss";
@import "shadcn/tailwind.css";
<div className="scroll-fade h-64 overflow-y-auto">…</div>
<div className="flex scroll-fade-x overflow-x-auto">…</div>

スクロールする任意の要素に追加します。端がフェードするのは、その先にさらにコンテンツがあるときだけなので、途切れた行は「スクロールを続けて」と伝え、静止したリストの端はくっきりしたままです。

フェードは mask-image なので、コンテンツは背後にあるものに溶け込みます。背景に合わせるオーバーレイのグラデーションが不要で、画像、色付きの面、ガラス調の面でも機能します。CSS のスクロール駆動アニメーションが、スクロールの最初と最後の96pxで各端のフェードを強めます。JavaScript は実行されず、再レンダリングも起きません。

  • 各フェードはコンテナーの12%で、上限は40pxです。
  • スクロール駆動アニメーションに対応しないブラウザーでは、両方のフェードが常に表示されます。精度はやや下がりますが、スクロールできることは伝わります。
  • scroll-fade-x、scroll-fade-s、scroll-fade-e は書字方向に従うため、右から左のレイアウトでは開始側のフェードが右に付きます。

水平

横にスクロールするフィルターの行。フェードだけで続きがあるとわかる場合は、同じく shadcn の CSS にある no-scrollbar と組み合わせます。

const topics = [
  "All",
  "Design",
  "Engineering",
  "Product",
  "Research",
  "Marketing",
  "Sales",
  "Support",
  "Operations",
  "Finance",
]

export function ScrollFadeHorizontal() {
  return (
    <div
      tabIndex={0}
      role="region"
      aria-label="Topics"
      className="no-scrollbar flex w-full max-w-sm scroll-fade-x gap-2 overflow-x-auto rounded-md outline-none focus-visible:ring-3 focus-visible:ring-focus-ring focus-visible:outline-hidden"
    >
      {topics.map((topic) => (
        <span
          key={topic}
          className="shrink-0 rounded-full bg-muted px-3 py-1.5 text-sm"
        >
          {topic}
        </span>
      ))}
    </div>
  )
}

片側の端

チャットは下端から始まるので、ヒントが必要なのは上にある古いメッセージだけです。scroll-fade-t は上端だけをフェードし、scroll-fade-t-16 はそれを高くします。

"use client"

const messages = Array.from({ length: 16 }, (_, index) => ({
  id: index,
  text: index % 3 === 0 ? "Sounds good, ship it." : "Pushed the fix to main.",
}))

export function ScrollFadeEdge() {
  return (
    <div className="w-full max-w-xs rounded-xl bg-muted">
      <ul
        ref={(node) => {
          if (node) {
            node.scrollTop = node.scrollHeight
          }
        }}
        tabIndex={0}
        aria-label="Messages"
        className="flex h-64 scroll-fade-t flex-col gap-2 overflow-y-auto rounded-xl p-3 text-sm outline-none scroll-fade-t-16 focus-visible:ring-3 focus-visible:ring-focus-ring focus-visible:outline-hidden"
      >
        {messages.map((message) => (
          <li
            key={message.id}
            className="w-fit max-w-[80%] shrink-0 rounded-2xl bg-background px-3 py-2 even:self-end even:bg-primary even:text-primary-foreground"
          >
            {message.text}
          </li>
        ))}
      </ul>
    </div>
  )
}
<div className="scroll-fade scroll-fade-16 overflow-y-auto">…</div>
<div className="scroll-fade scroll-fade-[20%] overflow-y-auto">…</div>
<div className="scroll-fade [--scroll-fade-reveal:12rem] overflow-y-auto">…</div>

サイズには、スペーシングスケール、または任意の長さやパーセンテージを指定できます。--scroll-fade-reveal は、端が完全にフェードするまでにスクロールする距離を設定します。

  • マスクは要素自身の背景と境界線もフェードします。例のように、面はラッパーに、フェードはスクロールする子要素に付けてください。
  • マスクはフォーカスリングを含め、端の近くのあらゆるものを隠します。フォーカスされた項目がフェードで見えなくならないよう、スクロールする要素にパディングを付けてください。
  • カスタムのスクロールバーも必要な場合は、代わりに Scroll area を使います。JavaScript で計測する独自のフェードを備え、すべてのブラウザーで動作します。
クラス説明
scroll-fade, scroll-fade-y上端と下端をフェードします。
scroll-fade-x方向に従って、開始端と終了端をフェードします。
scroll-fade-t, scroll-fade-b上端または下端だけをフェードします。
scroll-fade-s, scroll-fade-e開始端または終了端だけをフェードします。
scroll-fade-l, scroll-fade-r方向に関係なく、左端または右端だけをフェードします。
scroll-fade-<size>すべてのフェードのサイズ。
scroll-fade-{t,b,s,e}-<size>片側の端のフェードのサイズ。
scroll-fade-noneフェードをオフにします。たとえばブレークポイントで使います。
--scroll-fade-reveal端がフェードインするまでのスクロール距離。デフォルトは96pxです。