22 CSS Image Galleries21 / 22

Pure CSSMIT licensed

CSS Polaroid Stack Gallery

Photos styled as vintage Polaroid snapshots — thick white frame, deep bottom border, handwritten caption — scattered at playful angles and straightening with a lift on hover. The nostalgic photo-stack look boutique and wedding sites search for.

Published Updated

Live Demo
Try it

The code

<section class="gl-21" aria-label="Polaroid stack gallery">
  <div class="gl-21__pile">
    <figure class="gl-21__pola" tabindex="0"><img src="https://loremflickr.com/400/400/summer,friends?lock=2101" alt="Friends on a summer trip" loading="lazy" decoding="async"><figcaption>Summer '24</figcaption></figure>
    <figure class="gl-21__pola" tabindex="0"><img src="https://loremflickr.com/400/400/sunset?lock=2112" alt="Sunset on the beach" loading="lazy" decoding="async"><figcaption>Last light</figcaption></figure>
    <figure class="gl-21__pola" tabindex="0"><img src="https://loremflickr.com/400/400/roadtrip,car?lock=2103" alt="Road trip stop" loading="lazy" decoding="async"><figcaption>Route 1</figcaption></figure>
    <figure class="gl-21__pola" tabindex="0"><img src="https://loremflickr.com/400/400/picnic,park?lock=2104" alt="Picnic in the park" loading="lazy" decoding="async"><figcaption>Sunday</figcaption></figure>
    <figure class="gl-21__pola" tabindex="0"><img src="https://loremflickr.com/400/400/mountains,hike?lock=2105" alt="Mountain hike" loading="lazy" decoding="async"><figcaption>The climb</figcaption></figure>
  </div>
</section>
.gl-21,
.gl-21 *,
.gl-21 *::before,
.gl-21 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.gl-21 ::selection {
  background: oklch(0.6 0.12 40);
  color: #fff;
}

.gl-21 {
  --accent: oklch(0.55 0.13 40);
  font-family: 'Segoe UI',system-ui,sans-serif;
  width: 100%;
  min-height: 100vh;
  padding: 40px 20px;
  background: #d9cfc0;
  background-image: radial-gradient(rgba(120,100,80,.12) 1px,transparent 1px);
  background-size: 6px 6px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.gl-21__pile {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  justify-content: center;
  align-items: center;
  width: min(820px,100%);
}

.gl-21__pola {
  background: #fffdf8;
  padding: 12px 12px 44px;
  border-radius: 2px;
  width: 190px;
  box-shadow: 0 10px 24px -10px rgba(60,40,20,.5);
  transition: transform .35s cubic-bezier(.2,.7,.2,1),box-shadow .35s;
  outline: none;
}

.gl-21__pola img {
  display: block;
  width: 100%;
  aspect-ratio: 1/1;
  object-fit: cover;
  background: #e7e0d4;
  filter: sepia(.18) contrast(1.02);
}

.gl-21__pola figcaption {
  margin-top: 12px;
  text-align: center;
  font-family: 'Segoe Script','Bradley Hand',cursive;
  font-size: 17px;
  color: #5a4a38;
}

.gl-21__pola:nth-child(1) {
  transform: rotate(-6deg);
}

.gl-21__pola:nth-child(2) {
  transform: rotate(4deg);
}

.gl-21__pola:nth-child(3) {
  transform: rotate(-3deg);
}

.gl-21__pola:nth-child(4) {
  transform: rotate(5deg);
}

.gl-21__pola:nth-child(5) {
  transform: rotate(-5deg);
}

.gl-21__pola:hover,
.gl-21__pola:focus-visible {
  transform: rotate(0) scale(1.06);
  z-index: 5;
  box-shadow: 0 24px 44px -16px rgba(60,40,20,.6);
}

.gl-21__pola:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 4px;
}

@media (prefers-reduced-motion: reduce) {
  .gl-21__pola {
    transition: none;
  }
}
/* No JavaScript — nth-child rotations scatter the pile; hover straightens and lifts each print. */
Paste this into ChatGPT, Claude, Cursor, or any coding assistant. The block below is pre-framed with everything the AI needs to integrate this demo into your project — markup, styles, scoping notes, and the source URL. Hit Copy and paste straight into your chat.
Here's a working CSS Image Gallerie from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: CSS Polaroid Stack Gallery
Source: https://codefronts.com/snippets/css-image-gallery/css-polaroid-stack-gallery/

Photos styled as vintage Polaroid snapshots — thick white frame, deep bottom border, handwritten caption — scattered at playful angles and straightening with a lift on hover. The nostalgic photo-stack look boutique and wedding sites search for.
## HTML
```html
<section class="gl-21" aria-label="Polaroid stack gallery">
  <div class="gl-21__pile">
    <figure class="gl-21__pola" tabindex="0"><img src="https://loremflickr.com/400/400/summer,friends?lock=2101" alt="Friends on a summer trip" loading="lazy" decoding="async"><figcaption>Summer '24</figcaption></figure>
    <figure class="gl-21__pola" tabindex="0"><img src="https://loremflickr.com/400/400/sunset?lock=2112" alt="Sunset on the beach" loading="lazy" decoding="async"><figcaption>Last light</figcaption></figure>
    <figure class="gl-21__pola" tabindex="0"><img src="https://loremflickr.com/400/400/roadtrip,car?lock=2103" alt="Road trip stop" loading="lazy" decoding="async"><figcaption>Route 1</figcaption></figure>
    <figure class="gl-21__pola" tabindex="0"><img src="https://loremflickr.com/400/400/picnic,park?lock=2104" alt="Picnic in the park" loading="lazy" decoding="async"><figcaption>Sunday</figcaption></figure>
    <figure class="gl-21__pola" tabindex="0"><img src="https://loremflickr.com/400/400/mountains,hike?lock=2105" alt="Mountain hike" loading="lazy" decoding="async"><figcaption>The climb</figcaption></figure>
  </div>
</section>
```
## CSS
```css
.gl-21,
.gl-21 *,
.gl-21 *::before,
.gl-21 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.gl-21 ::selection {
  background: oklch(0.6 0.12 40);
  color: #fff;
}

.gl-21 {
  --accent: oklch(0.55 0.13 40);
  font-family: 'Segoe UI',system-ui,sans-serif;
  width: 100%;
  min-height: 100vh;
  padding: 40px 20px;
  background: #d9cfc0;
  background-image: radial-gradient(rgba(120,100,80,.12) 1px,transparent 1px);
  background-size: 6px 6px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.gl-21__pile {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  justify-content: center;
  align-items: center;
  width: min(820px,100%);
}

.gl-21__pola {
  background: #fffdf8;
  padding: 12px 12px 44px;
  border-radius: 2px;
  width: 190px;
  box-shadow: 0 10px 24px -10px rgba(60,40,20,.5);
  transition: transform .35s cubic-bezier(.2,.7,.2,1),box-shadow .35s;
  outline: none;
}

.gl-21__pola img {
  display: block;
  width: 100%;
  aspect-ratio: 1/1;
  object-fit: cover;
  background: #e7e0d4;
  filter: sepia(.18) contrast(1.02);
}

.gl-21__pola figcaption {
  margin-top: 12px;
  text-align: center;
  font-family: 'Segoe Script','Bradley Hand',cursive;
  font-size: 17px;
  color: #5a4a38;
}

.gl-21__pola:nth-child(1) {
  transform: rotate(-6deg);
}

.gl-21__pola:nth-child(2) {
  transform: rotate(4deg);
}

.gl-21__pola:nth-child(3) {
  transform: rotate(-3deg);
}

.gl-21__pola:nth-child(4) {
  transform: rotate(5deg);
}

.gl-21__pola:nth-child(5) {
  transform: rotate(-5deg);
}

.gl-21__pola:hover,
.gl-21__pola:focus-visible {
  transform: rotate(0) scale(1.06);
  z-index: 5;
  box-shadow: 0 24px 44px -16px rgba(60,40,20,.6);
}

.gl-21__pola:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 4px;
}

@media (prefers-reduced-motion: reduce) {
  .gl-21__pola {
    transition: none;
  }
}
```

## JavaScript
```js
/* No JavaScript — nth-child rotations scatter the pile; hover straightens and lifts each print. */
```

How this works

Each photo is a <figure> with generous padding and an extra-deep bottom padding to mimic the Polaroid's white frame, a soft drop box-shadow for the physical-print feel, and a handwritten-style caption in the bottom band. A per-card transform: rotate() (varied by nth-child) tosses them at casual angles.

On :hover/:focus-within the card rotates back to straight, scales up slightly and rises on z-index, as if picked up off the pile — all via transform, so it's smooth and reversible.

Make it yours

  • Change the resting angles in the nth-child rotations for more or less scatter.
  • Swap the caption font for a real handwriting webfont.
  • Deepen the frame by increasing the figure's bottom padding.
  • Overlap the cards with negative margins for a tighter physical stack.

Gotchas — read before shipping

  • Lift the hovered card's z-index so it rises above its neighbours instead of being clipped by them.
  • Keep captions real text (not baked into the image) for SEO and screen readers.
  • Straighten on :focus-within too so keyboard users get the same pick-up affordance.

Browser support

ChromeSafariFirefoxEdge
111+15.4+113+111+

Floor set by oklch() as this demo is written. The core technique itself goes back further — Chrome 36+.

transform rotate + box-shadow — universally supported; no modern features required.

Techniques used in this demo

Search CodeFronts

Loading…