22 CSS Image Carousels11 / 22

Pure CSSMIT licensed

Onboarding Tutorial Slider

A phone-width, swipeable onboarding flow with illustration, copy and indicator dots — the first-run tutorial pattern for mobile apps. Built on scroll-snap with the modern CSS ::scroll-marker dots, so pagination is generated by the browser with a graceful fallback.

Published

Live Demo
Try it

The code

<section class="car-11" aria-label="App onboarding">
  <div class="car-11__phone">
    <ol class="car-11__scroller" tabindex="0" role="group" aria-label="Onboarding steps, swipe or use arrow keys">
      <li class="car-11__step"><div class="car-11__art" style="background:linear-gradient(135deg,#6a5cff,#9b8bff)"><img src="https://picsum.photos/seed/onb-1/400/400" width="400" height="400" alt="Track your habits illustration"></div><h3 class="car-11__h">Track what matters</h3><p class="car-11__p">Log habits in two taps and watch streaks build over time.</p></li>
      <li class="car-11__step"><div class="car-11__art" style="background:linear-gradient(135deg,#00b3a4,#4fd1c5)"><img src="https://picsum.photos/seed/onb-2/400/400" width="400" height="400" alt="Get reminders illustration"></div><h3 class="car-11__h">Gentle reminders</h3><p class="car-11__p">Smart nudges at the right moment — never spammy, always optional.</p></li>
      <li class="car-11__step"><div class="car-11__art" style="background:linear-gradient(135deg,#ff7a59,#ffb057)"><img src="https://picsum.photos/seed/onb-3/400/400" width="400" height="400" alt="See progress illustration"></div><h3 class="car-11__h">See your progress</h3><p class="car-11__p">Weekly insights that show how far you've come, at a glance.</p></li>
    </ol>
  </div>
</section>
.car-11,
.car-11 *,
.car-11 *::before,
.car-11 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.car-11 ::selection {
  background: #6a5cff;
  color: #fff;
}

.car-11 {
  --accent: #6a5cff;
  font-family: 'Segoe UI',system-ui,sans-serif;
  width: 100%;
  min-height: 100vh;
  padding: 40px 20px;
  background: #eceafb;
  display: flex;
  align-items: center;
  justify-content: center;
}

.car-11__phone {
  width: 300px;
  max-width: 100%;
  background: #fff;
  border-radius: 34px;
  padding: 16px;
  box-shadow: 0 30px 60px -34px rgba(40,30,120,.6);
  border: 1px solid #e2ddf6;
}

.car-11__scroller {
  list-style: none;
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  border-radius: 22px;
  scrollbar-width: none;
  scroll-marker-group: after;
}

.car-11__scroller::-webkit-scrollbar {
  display: none;
}

.car-11__scroller:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 3px;
}

.car-11__step {
  flex: 0 0 100%;
  scroll-snap-align: center;
  padding: 8px 20px 20px;
  text-align: center;
}

.car-11__step::scroll-marker {
  content: "";
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: #c9c2f2;
  margin: 4px;
  cursor: pointer;
  border: 0;
  transition: transform .2s,background .2s;
}

.car-11__step::scroll-marker:target-current {
  background: var(--accent);
  transform: scale(1.35);
}

.car-11__scroller::scroll-marker-group {
  display: flex;
  justify-content: center;
  align-items: center;
  padding-top: 14px;
}

.car-11__art {
  aspect-ratio: 1/1;
  border-radius: 20px;
  overflow: hidden;
  margin-bottom: 22px;
}

.car-11__art img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  mix-blend-mode: luminosity;
  opacity: .9;
}

.car-11__h {
  font-size: 20px;
  font-weight: 800;
  color: #231d4a;
  margin-bottom: 8px;
}

.car-11__p {
  font-size: 14px;
  line-height: 1.55;
  color: #6b658c;
}

@media (prefers-reduced-motion: reduce) {
  .car-11__scroller {
    scroll-behavior: auto;
  }

  .car-11__step::scroll-marker {
    transition: none;
  }
}
/* No JavaScript — scroll-snap slider with browser-generated ::scroll-marker dots (Chromium 135+); slider works everywhere, dots are progressive enhancement. */
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 Carousel 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: Onboarding Tutorial Slider
Source: https://codefronts.com/snippets/css-image-carousel/onboarding-tutorial-slider/

A phone-width, swipeable onboarding flow with illustration, copy and indicator dots — the first-run tutorial pattern for mobile apps. Built on scroll-snap with the modern CSS ::scroll-marker dots, so pagination is generated by the browser with a graceful fallback.
## HTML
```html
<section class="car-11" aria-label="App onboarding">
  <div class="car-11__phone">
    <ol class="car-11__scroller" tabindex="0" role="group" aria-label="Onboarding steps, swipe or use arrow keys">
      <li class="car-11__step"><div class="car-11__art" style="background:linear-gradient(135deg,#6a5cff,#9b8bff)"><img src="https://picsum.photos/seed/onb-1/400/400" width="400" height="400" alt="Track your habits illustration"></div><h3 class="car-11__h">Track what matters</h3><p class="car-11__p">Log habits in two taps and watch streaks build over time.</p></li>
      <li class="car-11__step"><div class="car-11__art" style="background:linear-gradient(135deg,#00b3a4,#4fd1c5)"><img src="https://picsum.photos/seed/onb-2/400/400" width="400" height="400" alt="Get reminders illustration"></div><h3 class="car-11__h">Gentle reminders</h3><p class="car-11__p">Smart nudges at the right moment — never spammy, always optional.</p></li>
      <li class="car-11__step"><div class="car-11__art" style="background:linear-gradient(135deg,#ff7a59,#ffb057)"><img src="https://picsum.photos/seed/onb-3/400/400" width="400" height="400" alt="See progress illustration"></div><h3 class="car-11__h">See your progress</h3><p class="car-11__p">Weekly insights that show how far you've come, at a glance.</p></li>
    </ol>
  </div>
</section>
```
## CSS
```css
.car-11,
.car-11 *,
.car-11 *::before,
.car-11 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.car-11 ::selection {
  background: #6a5cff;
  color: #fff;
}

.car-11 {
  --accent: #6a5cff;
  font-family: 'Segoe UI',system-ui,sans-serif;
  width: 100%;
  min-height: 100vh;
  padding: 40px 20px;
  background: #eceafb;
  display: flex;
  align-items: center;
  justify-content: center;
}

.car-11__phone {
  width: 300px;
  max-width: 100%;
  background: #fff;
  border-radius: 34px;
  padding: 16px;
  box-shadow: 0 30px 60px -34px rgba(40,30,120,.6);
  border: 1px solid #e2ddf6;
}

.car-11__scroller {
  list-style: none;
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  border-radius: 22px;
  scrollbar-width: none;
  scroll-marker-group: after;
}

.car-11__scroller::-webkit-scrollbar {
  display: none;
}

.car-11__scroller:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 3px;
}

.car-11__step {
  flex: 0 0 100%;
  scroll-snap-align: center;
  padding: 8px 20px 20px;
  text-align: center;
}

.car-11__step::scroll-marker {
  content: "";
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: #c9c2f2;
  margin: 4px;
  cursor: pointer;
  border: 0;
  transition: transform .2s,background .2s;
}

.car-11__step::scroll-marker:target-current {
  background: var(--accent);
  transform: scale(1.35);
}

.car-11__scroller::scroll-marker-group {
  display: flex;
  justify-content: center;
  align-items: center;
  padding-top: 14px;
}

.car-11__art {
  aspect-ratio: 1/1;
  border-radius: 20px;
  overflow: hidden;
  margin-bottom: 22px;
}

.car-11__art img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  mix-blend-mode: luminosity;
  opacity: .9;
}

.car-11__h {
  font-size: 20px;
  font-weight: 800;
  color: #231d4a;
  margin-bottom: 8px;
}

.car-11__p {
  font-size: 14px;
  line-height: 1.55;
  color: #6b658c;
}

@media (prefers-reduced-motion: reduce) {
  .car-11__scroller {
    scroll-behavior: auto;
  }

  .car-11__step::scroll-marker {
    transition: none;
  }
}
```

## JavaScript
```js
/* No JavaScript — scroll-snap slider with browser-generated ::scroll-marker dots (Chromium 135+); slider works everywhere, dots are progressive enhancement. */
```

How this works

Steps are full-width snap panels in a scroll-snap-type:x mandatory scroller. The dot pagination uses the new CSS Carousel primitive: scroll-marker-group on the scroller plus a ::scroll-marker pseudo per item, so the browser renders one clickable dot per panel and tracks the active one via :target-current — no JS, no hand-written dots.

Where ::scroll-marker isn't supported yet, the scroller still snaps and swipes perfectly; the dots simply don't render, so nothing breaks. The scroller is focusable for keyboard paging.

Make it yours

  • Recolour dots via --accent in the ::scroll-marker and :target-current rules.
  • Add a step by adding one panel — the dot appears automatically.
  • Change panel width/height to match your device frame.
  • Swap the illustration block for a Lottie/video per step.

Gotchas — read before shipping

  • ::scroll-marker / scroll-marker-group ship in Chromium 135+; treat the dots as progressive enhancement and keep the scroller usable without them.
  • Keep panels exactly viewport-width so snapping lands cleanly one step at a time.
  • Provide a text 'Step N of M' or headings so progress isn't conveyed by dots alone.

Browser support

ChromeSafariFirefoxEdge
135+n/an/a135+

::scroll-marker + scroll-marker-group are new CSS Carousel features (Chromium 135+). The scroll-snap slider itself works everywhere; dots are progressive enhancement.

Techniques used in this demo

Search CodeFronts

Loading…