Fade Slider
Crossfade slideshow: the image on screen fades out while the next one fades in at the same place, with no movement at all. Arrows, keyboard and swipe.
Updated
This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. Gallery has 44 effects, including 6 free. Explore the category →
3 usage examples



How it works
Nothing slides here: the .fdsl-slide elements are stacked on top of each other (position: absolute; inset: 0) inside .fdsl-track. Only one carries the is-active class; it goes to opacity 1 while the others drop to 0, with a 0.6 s transition. Meanwhile both images blend, which suits views taken from the same angle.
The script moves is-active from one slide to another. It reacts to clicks on .fdsl-prev and .fdsl-next, to the ← and → keys while focus is in the slideshow, and to a horizontal drag of more than 50 px (Pointer Events, finger or mouse). After the last image comes the first, and the other way round. The slideshow stays still as long as nobody acts.
To start on another image than the first, put is-active on a different slide in the HTML: the script picks it up on load. Your photos go in as an <img> inside the slide (cropped with object-fit: cover); an optional .fdsl-caption shows in the middle. The frame takes the available width up to 640 px, in a 16/10 format.
Several slideshows on a page each work on their own: the script attaches to every .fdsl-carousel, creates nothing on window and skips a block it has already prepared (data-fdsl-ready) if it runs a second time.
Accessibility
- Announced structure:
role="region",aria-roledescription="carousel"and anaria-labelon the frame; each image becomes a "slide" group named "3 of 5". - Invisible images neutralised: slides at opacity 0 carry
inert,aria-hiddenandpointer-events: none; a link on a hidden photo can be neither clicked nor reached with the keyboard. - Screen readers: each change is said once by an invisible
aria-live="polite"area ("slide 2 of 5"). - Controls: native buttons labelled "Previous slide" and "Next slide", white focus ring, ← and → keys.
- Reduced motion: with
prefers-reduced-motion: reduce, the image changes at once, without the fade; navigation is untouched.
Browser compatibility
Under 4 KB of JavaScript, no library. Measured on 08/11/2026 (Playwright: Chromium, Firefox, WebKit): two slideshows side by side that do not respond to each other, code pasted twice without double wiring, Tab then Enter, arrow keys, finger swipe at 390 px in Chromium and mouse drag elsewhere, reduced motion, zero errors. Minimum versions from @mdn/browser-compat-data 8.1.8, set by the inert attribute.
Without inert (older browsers), the fade works, but the content of a hidden image can still receive focus. Safari 14 has no aspect-ratio: set the height with --fdsl-height. JavaScript off: only the is-active slide from the HTML is visible.
The code
HTML structure to paste into your page (the CSS + JS come with your purchase):
<div class="fx-0162-root">
<div class="fdsl-carousel" role="region" aria-roledescription="carousel" aria-label="Slideshow" data-slide="slide" data-of="of">
<div class="fdsl-track">
<div class="fdsl-slide is-active"><span class="fdsl-caption">Slide 1</span></div>
<div class="fdsl-slide"><span class="fdsl-caption">Slide 2</span></div>
<!-- … one div.fdsl-slide per image (img optional) -->
</div>
<button type="button" class="fdsl-arrow fdsl-prev" aria-label="Previous slide"><svg>…</svg></button>
<button type="button" class="fdsl-arrow fdsl-next" aria-label="Next slide"><svg>…</svg></button>
</div>
</div>
One-time payment, no subscription — the code is yours forever
Customize
Options passed to the API or data-* attributes:
| Option / property | Default | Effect |
|---|---|---|
Fade duration (CSS — --fdsl-duration on .fx-0162-root) |
0.6s | 1s or more gives a slideshow dissolve; 0.3s a brisk change. |
Width and format (CSS — --fdsl-width, --fdsl-ratio) |
640px · 16 / 10 | Maximum width of the frame and width/height ratio. 1 / 1 for square visuals. |
Imposed height (CSS — --fdsl-height) |
auto | A fixed height (160px) or 100% of the parent replaces the ratio-based height. |
Starting image (HTML — is-active class) |
first slide | Put is-active on the slide to show on load. |
Arrow background and corners (CSS — --fdsl-arrow-bg, --fdsl-radius) |
white at 20% · 1rem | On light images, a dark background (rgba(0,0,0,.4)) keeps the chevrons readable. |
Showcase area (CSS — --fdsl-stage-bg, --fdsl-stage-padding, --fdsl-stage-min-height) |
#0a0a0f · 25px 16px · 300px | Dark background and spacing of the demo; set transparent, 0, 0 in a real page. |
Spoken announcement (HTML — data-slide, data-of, aria-label) |
slide · of · Slideshow | Words used for "slide 2 of 5" and the slideshow's name; translate them for a page in another language. |
FAQ
#12121a) shows through a little. Give the .fdsl-carousel frame a background close to your images, or shorten the duration with --fdsl-duration.object-fit: cover to fill the frame. The fade simply looks best between photos with the same framing (a place at different hours, a product in several colours), because nothing moves except what changes.pointer-events: none and inert, so a button placed on a hidden image cannot be triggered by mistake through the one on top.