Scroll Stack <mv-scroll-stack>

Cards fixos que se empilham conforme você rola: cada card que chega se acomoda no lugar enquanto os de baixo recuam um degrau (menores, mais apagados), controlado pela rolagem onde há suporte; o foco revela os cards cobertos, e com movimento reduzido vira uma lista simples.

CategoriaRolagem
TipoWeb Component (<mv-scroll-stack>)
Statusestável
Keywordsstack, sticky, cards, deck, process, steps, scroll-driven, view-timeline

When to use

  • A sequence of process steps or case studies should stack as sticky cards while the page scrolls
  • A marketing section should present a few large cards one after another, with earlier ones receding behind
  • Cards hold links or buttons that keyboard users must be able to reach even once covered

Avoid when

  • Users should swipe or drag through a pile of cards rather than scroll past them → use Card Stack instead
  • Steps need a pinned visual that changes beside the text → use Sticky Scroll instead
  • There are many cards; beyond a handful the stack becomes a long, tiring scroll

Instalação

node scripts/add.mjs scroll-stack --out ./src/marvelous

Agente de IA com o servidor MCP do Marvelous UI: install_components({ slugs: ["scroll-stack"], target_dir: "<absolute path>/src/marvelous", framework: "react" }).

Arquivos copiados (dependências incluídas): tokens/tokens.css, core/base.css, core/element.js, core/motion.js, core/observe.js, components/scroll-stack/scroll-stack.js, components/scroll-stack/scroll-stack.css.

Uso

Marcação de referência, para usar como ponto de partida e personalizar com atributos, data-* e variáveis CSS:

<div id="mv-scroll-stack-demo" class="mv-scroll-area" data-orientation="vertical" tabindex="0" aria-label="Project process, scrollable">
  <style>
    #mv-scroll-stack-demo { width: min(100%, 44rem); height: 460px; margin-inline: auto; border: 1px solid var(--mv-border); border-radius: var(--mv-radius-xl); background: var(--mv-bg); }
    #mv-scroll-stack-demo .intro { padding: 2.25rem 1.75rem 1.5rem; }
    #mv-scroll-stack-demo .eyebrow { margin: 0; font: 500 .75rem/1 var(--mv-font-mono); letter-spacing: .08em; text-transform: uppercase; color: var(--mv-fg-muted); }
    #mv-scroll-stack-demo h2 { margin: .6rem 0 .5rem; font: 650 1.75rem/1.1 var(--mv-font-display); letter-spacing: -.035em; text-wrap: balance; }
    #mv-scroll-stack-demo .intro p { margin: 0; max-width: 30rem; color: var(--mv-fg-muted); font-size: .9rem; line-height: 1.55; }
    #mv-scroll-stack-demo mv-scroll-stack { padding-inline: 1.5rem; --mv-scroll-stack-top: 1.25rem; --mv-scroll-stack-gap: 1.5rem; }
    #mv-scroll-stack-demo .mv-scroll-stack-card { min-height: 15rem; display: grid; grid-template-rows: auto 1fr auto; gap: 1rem; padding: 1.75rem; }
    #mv-scroll-stack-demo .top { display: flex; align-items: center; justify-content: space-between; gap: 1rem; font: 500 .75rem/1 var(--mv-font-mono); color: var(--mv-fg-muted); }
    #mv-scroll-stack-demo .step { display: inline-flex; align-items: center; gap: .55rem; color: var(--mv-fg); }
    #mv-scroll-stack-demo .step::before { content: ""; width: .5rem; height: .5rem; border-radius: 50%; background: var(--mv-accent); }
    #mv-scroll-stack-demo h3 { margin: 0 0 .5rem; font: 650 1.4rem/1.15 var(--mv-font-display); letter-spacing: -.025em; }
    #mv-scroll-stack-demo .mv-scroll-stack-card p { margin: 0; max-width: 28rem; color: var(--mv-fg-muted); font-size: .9rem; line-height: 1.6; }
    #mv-scroll-stack-demo ul { display: flex; flex-wrap: wrap; gap: .4rem; margin: 0; padding: 1rem 0 0; list-style: none; border-top: 1px dashed var(--mv-border); }
    #mv-scroll-stack-demo li { padding: .25rem .6rem; border: 1px solid var(--mv-border); border-radius: var(--mv-radius-full); font-size: .75rem; color: var(--mv-fg-muted); }
    #mv-scroll-stack-demo .outro { padding: 0 1.75rem 3rem; color: var(--mv-fg-muted); font-size: .85rem; }
  </style>

  <div class="intro">
    <p class="eyebrow">How we work</p>
    <h2>Four steps, zero surprises</h2>
    <p>Scroll the panel: each step slides over the previous one, which settles back into the deck.</p>
  </div>

  <mv-scroll-stack>
    <article class="mv-scroll-stack-card" aria-labelledby="mv-ss-demo-1">
      <div class="top"><span class="step">Step 01</span><span>Week 1</span></div>
      <div>
        <h3 id="mv-ss-demo-1">Discovery</h3>
        <p>Stakeholder interviews, an audit of what already exists and a journey map. You leave with a ranked list of priorities.</p>
      </div>
      <ul aria-label="Deliverables"><li>Workshops</li><li>UX audit</li><li>Roadmap</li></ul>
    </article>
    <article class="mv-scroll-stack-card" aria-labelledby="mv-ss-demo-2">
      <div class="top"><span class="step">Step 02</span><span>Weeks 2-4</span></div>
      <div>
        <h3 id="mv-ss-demo-2">Design</h3>
        <p>Interactive mockups, a small design system and usability tests on a prototype before a single line of production code.</p>
      </div>
      <ul aria-label="Deliverables"><li>Prototype</li><li>Design system</li><li>User testing</li></ul>
    </article>
    <article class="mv-scroll-stack-card" aria-labelledby="mv-ss-demo-3">
      <div class="top"><span class="step">Step 03</span><span>Weeks 5-10</span></div>
      <div>
        <h3 id="mv-ss-demo-3">Build</h3>
        <p>Weekly releases to staging, code reviews on every change and accessibility checked continuously, not at the end.</p>
      </div>
      <ul aria-label="Deliverables"><li>Sprints</li><li>QA</li><li>WCAG 2.2 AA</li></ul>
    </article>
    <article class="mv-scroll-stack-card" aria-labelledby="mv-ss-demo-4">
      <div class="top"><span class="step">Step 04</span><span>Week 11</span></div>
      <div>
        <h3 id="mv-ss-demo-4">Launch</h3>
        <p>A guided go-live, analytics from day one and hands-on training so your team can take it from there.</p>
      </div>
      <ul aria-label="Deliverables"><li>Go-live</li><li>Analytics</li><li>Training</li></ul>
    </article>
  </mv-scroll-stack>

  <p class="outro">The deck is complete and scrolls away with the rest of the page.</p>
</div>

API

Attributes

NameTipoDescription
scrollerselector | windowReference scroll container. Default: the nearest scroll container, or the page. Setting it uses the scroll-listener path.
fallbackbooleanForces the scroll-listener path instead of the scroll-driven animation (tests, older engines).

Content structure

NameDescription
direct childrenThe cards, in stacking order.

CSS classes

NameDescription
mv-scroll-stack-cardDefault card look (optional): radius, raised surface, hairline border, shadow cast upward.

CSS variables

NameDefaultDescription
--mv-scroll-stack-topvar(--mv-space-6)Sticky position of the first card.
--mv-scroll-stack-offset0.85remVertical offset between two stacked cards.
--mv-scroll-stack-scale0.05Scale reduction per covering card (floor 0.5).
--mv-scroll-stack-dim0.1Dimming per covering card (capped at 0.45).
--mv-scroll-stack-enter0.03Extra scale an incoming card settles from while it slides over the previous one (0 = none).
--mv-scroll-stack-gapvar(--mv-space-8)Space between cards before stacking.
--mv-scroll-stack-tailvar(--mv-space-16)Margin after the last card: how long the full stack stays visible.
--mv-scroll-stack-i / -nCard index and count, written by the JS (read-only).

Accessibility

Reading and tab order unchanged; scrolling stays native (position: sticky, no scroll hijacking, no smooth-scroll library). Keyboard focus that lands in a covered card scrolls back just enough to show that card whole. Reduced motion: a plain list, nothing sticks, scales or dims. Forced colors: opaque outlined cards, no dimming.

Esta página foi traduzida com IA. Informar um problema de tradução