Gallery to Slideshow
CSS thumbnail grid switching to a sliding-window slideshow — cubic transitions, arrow + dot navigation, instant toggle.
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
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-motionblock 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 witharia-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 extraroleattribute needed. - No
roleoraria-labelis 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.
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):
<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>
Full HTML + CSS + JS, copy-paste ready — with hundreds of premium effects.
Customize
Options passed to the API or data-* attributes:
| Option / property | Default | Effect |
|---|---|---|
| `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
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()..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..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.