Cards✨ Premium

Gallery to Slideshow

CSS thumbnail grid switching to a sliding-window slideshow — cubic transitions, arrow + dot navigation, instant toggle.

CSSJSGallery

You'll get access to the interactive demo with a free account.

This effect is part of Effect.Labs — 811 vanilla effects, some free, some premium. Cards has 41 effects, including 6 free. Explore the category →

3 usage examples

🎈

① Photography portfolio — Landscape series gallery

WhenVisitors browse a portfolio organized in series: the grid gives the overview, the slideshow offers the full-frame experience of each image.
WhyThe translateX animation mimics sliding through a slide drawer — intuitive with no external lightbox or additional library.
Settings6 photos, .gallery-slideshow-wrapper height at 300 px, transition .4s ease for a more relaxed pace.
🎊

② Online magazine — Gallery embedded in a feature article

WhenA long-form article includes 4 to 6 field visuals to explore without leaving the reading column.
WhyThe compact grid does not interrupt reading flow; the slideshow unfolds each image to full column width with discreet navigation.
Settings4 thumbnails, grid repeat(2, 1fr), wrapper height 220 px.

③ E-commerce product page — Multi-angle image viewer

WhenThe product page displays 6 shots (front, side, detail, packaging) the buyer needs to inspect before purchasing.
WhyThe gallery gives an at-a-glance overview; the slideshow delivers the full-frame detail view without a modal or page change.
SettingsTransition .35s ease for immediate responsiveness, wrapper height 260 px.

How it works

The gallery/slideshow switch is entirely CSS-driven: setGalleryMode() adds .hidden to .gallery-grid-mode and .active to .gallery-slideshow-mode, toggling opacity and pointer-events in 400 ms — no JS animation, just declared CSS transitions.

The slideshow maintains a 3-slot sliding window: .slideshow-slide.prev (translateX(-120%) scale(0.8)), .slideshow-slide.current (translateX(0) scale(1)), .slideshow-slide.next (translateX(120%) scale(0.8)). On each navigation, updateSlideshow() reassigns backgrounds and classes to the 3 slots using modulo arithmetic on slideshowColors — the .6s cubic-bezier(.4,0,.2,1) transition declared on the slides does the rest.

The grid is a CSS Grid repeat(3, 1fr) over two rows with a 4 px gap. Thumbnails are <div> elements with an inline background; replace them with <img> or <picture> tags for real photos — the CSS structure and transitions stay identical.

Accessibility

  • No prefers-reduced-motion block is present in the CSS or JS — transitions run even when the user has requested reduced motion. Compensate in production by adding @media (prefers-reduced-motion: reduce) { .slideshow-slide { transition: none } }.
  • Arrow buttons carry aria-label="Slide précédente" / aria-label="Slide suivante" — keyboard and screen-reader accessible.
  • Navigation dots are native <button> elements with aria-label="Aller à la slide N" — focusable via Tab, activatable via Enter or Space.
  • Gallery / Slideshow toggle buttons are native <button> elements in the normal tab order, no extra role attribute needed.
  • No role or aria-label is set on the component wrapper — add one in production to identify the widget to assistive technologies.

Browser compatibility

Requires CSS Grid, CSS transitions, and CSS transforms — available in all modern browsers since 2017. Zero external dependencies.

Chrome 57+✓ Full
Firefox 52+✓ Full
Safari 10.1+✓ Full
Edge 16+✓ Full
Mobile iOS✓ Touch OK
Android Chrome✓ Full

Without CSS transition support, the gallery/slideshow switch is instant but functional. Without JS, the toggle buttons are inoperable and the grid stays in fixed gallery mode.

The code

HTML structure to paste into your page (CSS + JS available with a premium account):

index.html — structure
<div class="demo-preview">
  <div class="morph-toggle-group">
    <button class="morph-toggle active" onclick="setGalleryMode(this,'gallery')">Gallery</button>
    <button class="morph-toggle" onclick="setGalleryMode(this,'slideshow')">Slideshow</button>
  </div>
  <div class="gallery-slideshow-wrapper" id="galleryDemo">
    <div class="gallery-grid-mode" id="galleryGrid">
      <div class="gallery-thumb" style="background:…"></div>
      <!-- ×6 thumbnails -->
    </div>
    <div class="gallery-slideshow-mode" id="slideshowMode">
      <div class="slideshow-slide prev"></div>
      <div class="slideshow-slide current"></div>
      <div class="slideshow-slide next"></div>
      <button class="slideshow-arrow left" aria-label="Previous">‹</button>
      <button class="slideshow-arrow right" aria-label="Next">›</button>
      <div class="slideshow-nav"><!-- N× .slideshow-dot --></div>
    </div>
  </div>
</div>
🔒 Unlock the full code — from €2.99 the first month

Full HTML + CSS + JS, copy-paste ready — with hundreds of premium effects.

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
`slideshowColors` (JS global) 6 CSS gradients Array of background values for each slide — replace with url('photo.jpg') values for real images.
`.gallery-slideshow-wrapper` height 150px Total height of the component. Set to 100vh for a full-screen slideshow, or match your content column height.
`.slideshow-slide` transition .6s cubic-bezier(.4,0,.2,1) Duration and curve of the slide animation. .35s ease for more responsiveness, 1s for a cinematic transition.
`.gallery-grid-mode` grid-template-columns repeat(3, 1fr) Number of grid columns. repeat(2, 1fr) for 4 images over 2 rows, repeat(4, 1fr) for 8 images over 2 rows.
`--primary` (`:root`) #6366f1 Accent color for the active toggle button (Gallery / Slideshow). Replace with your brand color.
`.slideshow-slide` border-radius 10px Corner radius of slides in full-frame view. 0 for edge-to-edge slides.
`.gallery-thumb` border-radius 4px Corner radius of thumbnails in the grid. 0 for strict square thumbnails.

FAQ

Call directly: document.getElementById('galleryGrid').classList.add('hidden'); document.getElementById('slideshowMode').classList.add('active'); updateSlideshow(); — no user interaction required. Make sure slideshowColors and slideshowIndex are defined before calling updateSlideshow().
Yes. On each .gallery-thumb, replace style="background:…" with an <img style="width:100%;height:100%;object-fit:cover"> tag, and populate slideshowColors with url('photo.jpg') center/cover no-repeat values. The rest of the JS and CSS is unchanged.
Add .gallery-thumb elements to #galleryGrid and extra .slideshow-dot buttons to .slideshow-nav. Extend slideshowColors with as many entries as there are slides — updateSlideshow() computes prev/current/next indices using modulo on the array length, no other changes needed.