粘性堆叠卡片

滚动时,每张卡片都停在比上一张略低的位置,前面的卡片缩小,整齐地叠成一摞。

  • CSS
  • 布局
  • 滚动
  • 收录于
在框内滚动 ↓
01需求
02草图
03开发
04上线

AI 提示词

用 CSS 在 React 中制作滚动时堆叠的卡片。给每张卡片设置 position: sticky 和 top: calc(16px + var(--i) * 14px),让后面的卡片停在略低的位置,像一副牌一样压住前面的卡片。用滚动驱动动画让被覆盖的卡片缩小:animation: shrink linear both; animation-timeline: view(); animation-range: exit-crossing 0% exit-crossing 60%;,keyframe 终点为 transform: scale(0.9) 和 filter: brightness(0.7)。为不支持 animation-timeline 的浏览器保留降级效果(只堆叠不缩小)。卡片是编号步骤“需求”“草图”“开发”“上线”。在 prefers-reduced-motion 下保留粘性堆叠,去掉缩放。

源代码

Demo.tsx
'use client'

import s from './demo.module.css'

export default function StickyStack({ labels }: { labels: Record<string, string> }) {
  const steps = labels.steps.split('|')
  return (
    <div className={s.frame} tabIndex={0} aria-label={labels.hint}>
      <span className={s.hint}>{labels.hint} ↓</span>
      {steps.map((step, i) => (
        <article key={step} className={s.card} style={{ '--i': i } as React.CSSProperties}>
          <span className={s.n}>{String(i + 1).padStart(2, '0')}</span>
          <strong className={s.step}>{step}</strong>
        </article>
      ))}
      <div className={s.end} />
    </div>
  )
}
demo.module.css
.frame {
  position: absolute;
  inset: 0;
  display: grid;
  justify-items: center;
  gap: 28px;
  padding: 16px;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
}

.frame:focus-visible { outline: 2px solid var(--color-focus); outline-offset: -4px; }

.hint { font: 500 var(--text-xs) / 1 var(--font-mono); letter-spacing: 0.06em; text-transform: uppercase; color: var(--stage-muted); }

.card {
  position: sticky;
  top: calc(16px + var(--i) * 14px);
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: min(240px, 100%);
  height: 110px;
  padding: 0 20px;
  border: 1px solid var(--stage-rule);
  border-radius: 16px;
  background: var(--stage-surface);
  color: var(--stage-ink);
  transform-origin: 50% 0;
}

.card:nth-of-type(even) { background: var(--stage-ink); color: var(--stage-bg); }

@supports (animation-timeline: view()) {
  .card {
    animation: shrink linear both;
    animation-timeline: view();
    animation-range: exit-crossing 0% exit-crossing 60%;
  }
}

@keyframes shrink { to { transform: scale(0.9); filter: brightness(0.7); } }

.n { font: 500 var(--text-sm) / 1 var(--font-mono); color: var(--stage-accent); }
.step { font: 600 var(--text-xl) / 1 var(--font-display); }

.end { height: 120px; }

@media (prefers-reduced-motion: reduce) {
  .card { animation: none; }
}

投稿创意

看到想收录的动效或主题?简单描述一下,会打开一个预先填好的 GitHub Issue,确认后即可提交。

你想投稿的是?

需要 GitHub 账号,投稿内容会公开。