CSS-only Fading Slideshow

Here's how to make a slideshow with just css.

The Markup

Create a container and the images that you want in your slideshow as direct children:

<div class="slideshow">
  <img src="/photo-1.jpg" alt="photo"/>
  <img src="/photo-2.jpg" alt="photo"/>
  <img src="/photo-3.jpg" alt="photo"/>
  <img src="/photo-4.jpg" alt="photo"/>
  <img src="/photo-5.jpg" alt="photo"/>

The Styles

The styles are dependent upon the number of slide in the slideshow. This example shows 5 slides. The animation timings are also dependent on the length of time that each slide is shown. Here, each slide is shown for 6 seconds. The slideshow will cycle fully in 60 seconds (5*6=30).

First, the keyframe animation: This controls the fade:

@keyframes slideshow__fade {
  0% {
    opacity: 0;
    z-index: 2;
  6.6666666667% {
    opacity: 1;
  26.6666666667% {
    opacity: 1;
  27.6666666667% {
    opacity: 0;
    z-index: 1;
  100% {
    opacity: 0;

Then the parent element style: The images are stacked, so that they can cross-fade, so they'll be positioned absolute, relative to the parent container:

.slideshow {
  position: relative;

Next, the images in general are going to be styled, getting absolute positioned and having the animation applied. Notably, the first slide is not positioned absolutely. This is so we can get the .slideshow not to collapse. It will take the height of the first slide. (Constraint: This will work best if all the slides are of equal height.):

.slideshow img:not(:first-child) {
  position: absolute;
  left: 0;
  top: 0;
  margin: 0 auto;
  animation-duration: 30s;
  animation-fill-mode: both;
  animation-iteration-count: infinite;
  animation-name: slideshow__fade;
  animation-timing-function: ease-in;
  transition: opacity 2s ease-in;

Finally, we delay the slides in turn so that they start fading in sequence. The first slide starts right away. The 2nd slide after the 6s mark, then multiples of 6s thereafter:

.slideshow img:nth-child(1) {
  animation-delay: 0s;
.slideshow img:nth-child(2) {
  animation-delay: 6s;
.slideshow img:nth-child(3) {
  animation-delay: 12s;
.slideshow img:nth-child(4) {
  animation-delay: 18s;
.slideshow img:nth-child(5) {
  animation-delay: 24s;

And there it is. It fades. It's CSS. JavaScript bytes did not cross the wire.