30 CSS Grid Layouts27 / 30

Pure CSSMIT licensed

Scroll-Snap Slider

A native-feeling carousel with zero carousel library: a column-flow grid inside a snap container, slides centered by scroll-snap-align, momentum and touch physics free from the browser. Edge peeking shows there's more to scroll — the affordance JS sliders fake with padding math.

Published Updated

Live Demo
Try it

The code

<section class="cgl-27" aria-label="Scroll snap slider demo">
  <div class="cgl-27__rail" role="group" aria-label="Featured slides">
    <article class="cgl-27__slide" tabindex="0" style="--g:linear-gradient(130deg,oklch(0.55 0.16 330),oklch(0.3 0.1 300))"><h4>Native physics</h4><p>Momentum, rubber-band, touch — all free.</p></article>
    <article class="cgl-27__slide" tabindex="0" style="--g:linear-gradient(130deg,oklch(0.5 0.15 260),oklch(0.28 0.09 290))"><h4>snap-align: center</h4><p>The browser settles each slide mid-view.</p></article>
    <article class="cgl-27__slide" tabindex="0" style="--g:linear-gradient(130deg,oklch(0.55 0.14 200),oklch(0.3 0.08 240))"><h4>78% columns</h4><p>Neighbours peek — the honest 'more here' cue.</p></article>
    <article class="cgl-27__slide" tabindex="0" style="--g:linear-gradient(130deg,oklch(0.6 0.13 150),oklch(0.32 0.08 180))"><h4>Zero libraries</h4><p>Delete the carousel dependency.</p></article>
  </div>
</section>
.cgl-27,
.cgl-27 *,
.cgl-27 *::before,
.cgl-27 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.cgl-27 {
  width: 100%;
  min-height: 100vh;
  --bg: oklch(0.14 0.02 310);
  font-family: system-ui,sans-serif;
  background: var(--bg);
  padding: 1.6rem 0;
}

.cgl-27 .cgl-27__rail {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 78%;
  gap: 14px;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  padding-inline: 11%;
  padding-block-end: 10px;
  scrollbar-width: thin;
  scrollbar-color: oklch(0.5 0.1 310) transparent;
}

.cgl-27 .cgl-27__slide {
  scroll-snap-align: center;
  aspect-ratio: 16/8;
  border-radius: 18px;
  background: var(--g);
  padding: 1.4rem;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: .4rem;
  border: 1px solid oklch(1 0 0/.14);
}

.cgl-27 h4 {
  font-size: 1.1rem;
  color: white;
}

.cgl-27 .cgl-27__slide p {
  font-size: .8rem;
  color: oklch(0.85 0.03 310);
}

.cgl-27 .cgl-27__slide:focus-visible {
  outline: 3px solid oklch(0.8 0.14 330);
  outline-offset: 3px;
}
/* No JavaScript — a column-flow grid in a snap container; the browser supplies all carousel physics. */
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 Grid Layout 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: Scroll-Snap Slider
Source: https://codefronts.com/layouts/css-grid-layouts/scroll-snap-slider/

A native-feeling carousel with zero carousel library: a column-flow grid inside a snap container, slides centered by scroll-snap-align, momentum and touch physics free from the browser. Edge peeking shows there's more to scroll — the affordance JS sliders fake with padding math.
## HTML
```html
<section class="cgl-27" aria-label="Scroll snap slider demo">
  <div class="cgl-27__rail" role="group" aria-label="Featured slides">
    <article class="cgl-27__slide" tabindex="0" style="--g:linear-gradient(130deg,oklch(0.55 0.16 330),oklch(0.3 0.1 300))"><h4>Native physics</h4><p>Momentum, rubber-band, touch — all free.</p></article>
    <article class="cgl-27__slide" tabindex="0" style="--g:linear-gradient(130deg,oklch(0.5 0.15 260),oklch(0.28 0.09 290))"><h4>snap-align: center</h4><p>The browser settles each slide mid-view.</p></article>
    <article class="cgl-27__slide" tabindex="0" style="--g:linear-gradient(130deg,oklch(0.55 0.14 200),oklch(0.3 0.08 240))"><h4>78% columns</h4><p>Neighbours peek — the honest 'more here' cue.</p></article>
    <article class="cgl-27__slide" tabindex="0" style="--g:linear-gradient(130deg,oklch(0.6 0.13 150),oklch(0.32 0.08 180))"><h4>Zero libraries</h4><p>Delete the carousel dependency.</p></article>
  </div>
</section>
```
## CSS
```css
.cgl-27,
.cgl-27 *,
.cgl-27 *::before,
.cgl-27 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.cgl-27 {
  width: 100%;
  min-height: 100vh;
  --bg: oklch(0.14 0.02 310);
  font-family: system-ui,sans-serif;
  background: var(--bg);
  padding: 1.6rem 0;
}

.cgl-27 .cgl-27__rail {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 78%;
  gap: 14px;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  padding-inline: 11%;
  padding-block-end: 10px;
  scrollbar-width: thin;
  scrollbar-color: oklch(0.5 0.1 310) transparent;
}

.cgl-27 .cgl-27__slide {
  scroll-snap-align: center;
  aspect-ratio: 16/8;
  border-radius: 18px;
  background: var(--g);
  padding: 1.4rem;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: .4rem;
  border: 1px solid oklch(1 0 0/.14);
}

.cgl-27 h4 {
  font-size: 1.1rem;
  color: white;
}

.cgl-27 .cgl-27__slide p {
  font-size: .8rem;
  color: oklch(0.85 0.03 310);
}

.cgl-27 .cgl-27__slide:focus-visible {
  outline: 3px solid oklch(0.8 0.14 330);
  outline-offset: 3px;
}
```

## JavaScript
```js
/* No JavaScript — a column-flow grid in a snap container; the browser supplies all carousel physics. */
```

How this works

The rail is grid-auto-flow: column; grid-auto-columns: 78% inside overflow-x: auto; scroll-snap-type: x mandatory. Each slide's scroll-snap-align: center makes the browser settle it mid-viewport — with 78% columns, the neighbours peek 11% on each side. All physics (momentum, rubber-banding, touch, trackpad, keyboard) is native scrolling, which no JS carousel replicates faithfully.

scroll-behavior: smooth upgrades anchor jumps if you add prev/next links; overscroll-behavior-x: contain keeps a swipe past the last slide from triggering browser back-navigation. Slides are focusable <article>s so keyboard users can Tab through — and because it's real scrolling, Tab automatically brings each slide into view.

Make it yours

  • Peek amount = 100% − auto-columns %; 90% columns ≈ subtle 5% peeks.
  • Snap start instead of center for gallery-style leading alignment (pair with scroll-padding-inline).
  • Add prev/next as anchor links to slide ids — smooth-scrolled by the browser.
  • Stack a dot indicator with scroll-driven animations (scroll-timeline) where supported — pure-CSS active dots.

Gotchas — read before shipping

  • mandatory snap on content TALLER than the viewport traps vertical scrolling — for mixed-height slides use proximity.
  • Don't hide the scrollbar without providing visible affordance (the peeks do that here); invisible scrolling fails discoverability.
  • iOS momentum + mandatory snap occasionally skips a slide on hard flicks — acceptable native behaviour, don't fight it with JS.

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 69+.

Scroll snap has been interoperable since 2019 — this is among the most deployable demos in the set.

Techniques used in this demo

Search CodeFronts

Loading…