webdevpuneet.com

Scroll Polaroid Stack Flip — Free HTML CSS JS Snippet

Scroll Polaroid Stack Flip · Scroll · Plain HTML, CSS & JS · Live preview

Copy & paste

Source Code

<div class="hint">Scroll ↓ to sort the photo stack</div>
<div class="polaroid-wrap">
  <div class="polaroid-stage">
    <div class="grid-slots" id="gridSlots">
      <div class="slot" style="--gx:0;--gy:0"></div>
      <div class="slot" style="--gx:1;--gy:0"></div>
      <div class="slot" style="--gx:2;--gy:0"></div>
      <div class="slot" style="--gx:0;--gy:1"></div>
      <div class="slot" style="--gx:1;--gy:1"></div>
      <div class="slot" style="--gx:2;--gy:1"></div>
    </div>
    <div class="stack" id="stack">
      <div class="polaroid" style="--hue:200;--mr:-8deg" data-photo="1"><div class="photo"></div><div class="caption">Beach Day</div></div>
      <div class="polaroid" style="--hue:20;--mr:6deg" data-photo="2"><div class="photo"></div><div class="caption">Road Trip</div></div>
      <div class="polaroid" style="--hue:280;--mr:-4deg" data-photo="3"><div class="photo"></div><div class="caption">Sunset</div></div>
      <div class="polaroid" style="--hue:100;--mr:9deg" data-photo="4"><div class="photo"></div><div class="caption">Friends</div></div>
      <div class="polaroid" style="--hue:340;--mr:-11deg" data-photo="5"><div class="photo"></div><div class="caption">Camping</div></div>
      <div class="polaroid" style="--hue:50;--mr:5deg" data-photo="6"><div class="photo"></div><div class="caption">City Lights</div></div>
    </div>
  </div>
</div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

Randomized per-card rotation via CSS custom properties for an authentic messy pile
Real grid target positions measured at runtime with getBoundingClientRect, not hardcoded
Two-part peel-then-settle motion using 3D rotateX and perspective for a lifted feel
Sequential fractional-timeline segments stagger each card's turn
Ascending z-index keeps stack order visually correct before cards peel away
Fully reversible — cards lift back out of the grid and return to the messy pile on scroll-up
Warm cream/kraft-paper color palette with soft box-shadow depth
Responsive stack and grid sizing at the 640px breakpoint

About this UI Snippet

Scroll Polaroid Stack Flip — getBoundingClientRect Targeting & 3D Peel-and-Settle Motion

Screenshot of the Scroll Polaroid Stack Flip snippet rendered live

This snippet starts with a messy pile of randomly-rotated polaroid photo cards and, as the user scrolls, peels them off one at a time with a subtle 3D lift before flying each one into its own cell of a neat underlying grid — a satisfying "getting organized" transformation.

Randomized resting rotation via CSS custom properties

Each .polaroid sets its own --mr (mess rotation) custom property consumed by transform: rotate(var(--mr)), giving the initial pile a natural, hand-tossed look where no two photos sit at the same angle — all defined inline in the HTML so the messy arrangement is easy to art-direct per photo.

Measuring real target positions with getBoundingClientRect

Rather than hardcoding each photo's final grid position, a hidden .grid-slots CSS Grid layout defines the actual target cells, and getSlotOffset() measures the pixel offset from the stack's origin to each slot using getBoundingClientRect() at runtime — so the grid can be reflowed (different columns, gaps, or a responsive breakpoint) without ever touching the animation's position math.

Two-part motion per card: peel, then settle

Each polaroid's segment is split into two tweens: first a small lift-and-tilt (rotateX: -40, scale: 1.05, a negative y and boosted zIndex) simulating a card being physically picked up off the pile with a 3D peel using transform-style: preserve-3d and the stage's perspective, then a second tween flying it to its measured grid offset while resetting rotation and scale to flat and neutral — reading as the photo being placed down into its slot.

Sequential ordering via fractional timeline segments

The familiar segStart = i / n pattern (also used in Scroll Book Shelf Slide and Scroll Terrain Contour Lines) gives each polaroid its own slice of the scroll range so they peel and settle one after another rather than all at once, with ascending zIndex ensuring later cards in the original stack visually sit on top while still in the pile.

Fully reversible

Every tween lives on one scrub: true timeline, so scrolling back up lifts each photo back out of its grid slot, tilts it back in 3D, and drops it back into its messy pile position and rotation — undoing the sort in reverse order.

Pair this with Scroll Card Deck Shuffle for a related stack-transformation technique.

Step by step

How to Use

  1. 1
    Scroll through the previewScroll down slowly — each polaroid lifts off the messy pile with a 3D tilt, then flies into its own slot in the neat grid below.
  2. 2
    Add or remove photosAdd a .polaroid element to #stack with its own --hue and --mr custom properties, and a matching .slot element to #gridSlots — the JS reads both arrays' lengths automatically.
  3. 3
    Use real photosReplace the .photo div's gradient background with an <img> or background-image pointing at your own image.
  4. 4
    Change the grid layoutEdit grid-template-columns/rows on .grid-slots — getSlotOffset() measures actual rendered slot positions, so any grid layout works without touching the JS.
  5. 5
    Adjust the peel height and tiltChange the rotateX, scale and y values in the first tween of each card's segment to make the peel more or less dramatic.
  6. 6
    Export in your formatClick "HTML" for a standalone file, "JSX" for a React component, or "Tailwind" for a React + Tailwind version.

Real-world uses

Common Use Cases

Photo gallery or portfolio organization reveal
A literal "sorting the mess into order" animation for a photography portfolio or gallery landing page.
Memory or social app onboarding
Use the peel-and-sort motion to represent photos being organized into albums in a memories or social app.
Scrapbook or travel-journal storytelling
A nostalgic, hand-placed aesthetic well suited to travel journals, scrapbook sites, or personal blogs.
Team or testimonial grid reveal
Repurpose each polaroid as a team member photo or testimonial card that organizes into a neat grid.
Learn runtime-measured animation targets
Study how getBoundingClientRect lets an animation target a real, reflow-aware layout instead of hardcoded coordinates.
Learn 3D peel/lift transforms
See how perspective plus rotateX and preserve-3d combine to simulate an object being physically lifted off a surface.

Got questions?

Frequently Asked Questions

A hidden CSS Grid of .slot elements defines the real target layout. getSlotOffset() measures each slot's position relative to the stack's origin with getBoundingClientRect() at runtime, so the animation always targets the grid's actual rendered position rather than a hardcoded coordinate.

The stage has a CSS perspective set, each card has transform-style: preserve-3d, and the first tween in each card's segment applies a negative rotateX along with a slight scale-up and lift — combined, this reads as the card tilting up and off the pile in 3D before flying to its slot.

Yes — edit grid-template-columns/rows on .grid-slots and add matching .slot elements; since positions are measured live with getBoundingClientRect, no animation code needs to change.

Replace each .photo div's CSS gradient background with a background-image or swap it for an <img> tag sized to fill the same area — the surrounding polaroid frame and caption styling stay the same.

Call ScrollTrigger.refresh() after a resize (or listen for a resize event) so getSlotOffset() re-measures the slots' new positions; the snippet already calls refresh() once on load to establish correct initial positions.