Rejouice — loading0

Sticky panel stack

Sequential panels that each stick to the viewport while the next one slides up over them, like cards being dealt onto a pile.

Grade: ARuntimes: css · gsapStatus: live
Loading demo…
Sticky panel stack — scroll inside the frameOpen standalone ↗

Intent

Turns a linear list of three to five ideas into a paced sequence. Each panel gets the reader's full attention for a fixed scroll distance, and the overlap makes the transition between ideas feel authored rather than incidental.

Implementation

`--panel-index` drives z-index, so adding a panel means adding one attribute rather than editing a stylesheet.

Dependencies: none

html-css-js
<section class="stack">
  <div class="stack__slot" style="--panel-index: 0">
    <article class="stack__panel"></article>
  </div>
  <div class="stack__slot" style="--panel-index: 1">
    <article class="stack__panel"></article>
  </div>
  <div class="stack__slot" style="--panel-index: 2">
    <article class="stack__panel"></article>
  </div>
</section>

<style>
/* No overflow clipping anywhere in the ancestor chain, or sticky breaks. */
.stack { display: grid; }

.stack__slot {
  /* The slot supplies scroll distance; the panel inside stays pinned. */
  height: 200svh;
  z-index: var(--panel-index);
  position: relative;
}

.stack__panel {
  position: sticky;
  top: 0;
  min-height: 100svh;
  display: grid;
  align-content: center;
  gap: var(--space-md);
  padding: var(--space-xl) var(--gutter);
  background: var(--bg);
  border-block-start: 1px solid var(--line);
}
</style>

Use it when

  • Three to five steps in a process, or three to five product pillars.
  • When the items are peers and the order matters.

Avoid it when

  • With more than five panels — the section becomes a scroll tax.
  • When any panel's content is taller than the viewport, since the sticky panel will clip it.

Accessibility

  • This is pure CSS sticky, so it degrades to a normal stacked list — that is the reduced-motion behaviour and it needs no extra handling.
  • Ensure each panel's content fits within `100svh` at the smallest supported width, or it becomes unreachable.
  • Keyboard focus moving into an off-screen panel must scroll it into view; do not use `overflow: hidden` on the wrapper.

Performance

  • Zero JavaScript, zero scroll listeners.
  • Avoid `backdrop-filter` on the panels — compositing a full-viewport blur on every frame of a sticky scroll is the most common cause of jank in this pattern.

Knobs

scroll per panel
Wrapper height beyond the sticky child. Default: 100svh
peek
How much of the previous panel stays visible. Default: 0

Composition

Instruction for Claude Code

Build a sticky panel stack: each panel sits in a 200svh slot with position relative and a z-index from a --panel-index custom property; the panel itself is position sticky at top 0 with min-height 100svh and an opaque background. Do not put overflow hidden or clip on any ancestor. Keep panel content shorter than one viewport. Use no JavaScript and no backdrop-filter.