27

I want to fade between images in a loop (like result here-jsfiddle.net/5M2PD) but purely through CSS, no JavaScript. I tried using key-frames but I wasn't successful. Please Help.

@keyframes cf3FadeInOut {
    0% {
        opacity:1;
    }
    45% {
        opacity:1;
    }
    55% {
        opacity:0;
    }
    100% {
        opacity:0;
    }
}

#cf3 img.top {
   animation-name: cf3FadeInOut;
   animation-timing-function: ease-in-out;
   animation-iteration-count: infinite;
   animation-duration: 10s;
   animation-direction: alternate;
}
5
  • Maybe an interesting idea for the future, but I don't think most current browsers will like @keyframes - even more because most people don't use the latest versions. Commented Jul 30, 2013 at 19:05
  • Thank you MightyPork for the suggestion. Is there any other alternative? for CSS only? Commented Jul 30, 2013 at 19:10
  • I don't think so.. personally, I'd stick to JS, but if that's not an option, I don't know. Commented Jul 30, 2013 at 19:11
  • animation is still prefixed in most browsers (-webkit-animation, -webkit-keyframes), which could be part of your problem. To clarify, you're going to apply top to the next image, and then you want that one to fade in? You could use transition for that, instead of animation. Commented Jul 30, 2013 at 19:38
  • there's a helpful post on how to do this here: devtwins.com/blog/css-cross-fading-images Commented Dec 14, 2021 at 18:27

3 Answers 3

40

I have taken your fiddle as a base, and made it work without script.

updated demo

I needed to set an id to the HTML

.fadein img {
    position:absolute;
    top:0;
    -webkit-animation-name: fade;
    -webkit-animation-iteration-count: infinite;
    -webkit-animation-duration: 6s;
    animation-name: fade;
    animation-iteration-count: infinite;
    animation-duration: 6s;
}

@-webkit-keyframes fade {
    0% {opacity: 0;}
    20% {opacity: 1;}
    33% {opacity: 1;}
    53% {opacity: 0;}
    100% {opacity: 0;}
}
@keyframes fade {
    0% {opacity: 0;}
    20% {opacity: 1;}
    33% {opacity: 1;}
    53% {opacity: 0;}
    100% {opacity: 0;}
}

#f1 {
    background-color: lightblue;
}
#f2 {
    -webkit-animation-delay: -4s;
    background-color: yellow;
}
#f3 {
    -webkit-animation-delay: -2s;
    background-color: lightgreen;
}
<div class="fadein">
    <img id="f3" src="http://i.imgur.com/R7A9JXc.png">
    <img id="f2" src="http://i.imgur.com/D5yaJeW.png">
    <img id="f1" src="http://i.imgur.com/EUqZ1Er.png">
</div>

I am setting the keyframes to give aprox 1/3 of the time visible, with apropiate transitions. Then I set different delays for every image, so that they alternate. If you want full browser support, you will need more vendor prefixes. I have used -webkit- and bare property so that you get the idea.

Sign up to request clarification or add additional context in comments.

6 Comments

Nice! How can I set up this for only two images? I can't find out, I have tried to remove <img id="f3" src="http://i.imgur.com/R7A9JXc.png"> from the markup and #f3 { -webkit-animation-delay: -2s; background-color: lightgreen; } from the CSS code. But it does not work.
@alessadro the keyframes change opacity at 33% because there are 3 elements. You need to change this to 50% to adjust for 2 elements
@candlejack For 2 elements instead of 3, remove all mentions of f3 as you have done already, and change the -webkit-animation-delay on #f2 to -2s. Finally, change the -webkit-animation-duration (and animation-duration) to 4s.
Working great on latest Chrome, Firefox, Edge browsers.
can use nth-of-type over #f1 nowadays jsfiddle.net/4d1uwj5f
|
4

I've made a dynamic solution with SASS. It's possible to configure:

  • Total animation time
  • Amount of items
  • Transition speed

It automatically calculates the keyframe percentages and delays between items.

Codepen.io demo

// Demo styles
.fadecycle div {
  opacity: 0;
  position: absolute;
  width: 200px;
  line-height: 200px;
  text-align: center;
}

.fadecycle div:nth-child(1) { background: lightsalmon; }
.fadecycle div:nth-child(2) { background: lightsteelblue; }
.fadecycle div:nth-child(3) { background: lightseagreen; }
.fadecycle div:nth-child(4) { background: lightskyblue; }

// Animation settings
$totalTime: 8s;
$items: 4;
$transitionSpeed: 1.5;

// Calculate transition + display time in seconds
$transitionTime: 0s + $totalTime / ($items * $transitionSpeed * 2);
$displayTime: (0s + $totalTime - ($transitionTime * $items)) / $items;

// Set transition for each element
@for $i from 1 through $items {
  .fadecycle div:nth-child(#{$i}) {
    // Delay is increased for each item
    // starting with an offset of -$transitionTime so the first element is displayed on load
    $delay: -$transitionTime + ($transitionTime + $displayTime) * ($i - 1);
    animation: fadeinout $totalTime linear $delay infinite;
  }
}

// Calculate percentages of the times for keyframes
$transitionPercentage: 0% + 100 * ($transitionTime / $totalTime);
$displayPercentage: 0% + 100 * ($displayTime / $totalTime);

@keyframes fadeinout {
  0% {
    opacity: 0;
  }
  #{$transitionPercentage},
  #{$transitionPercentage + $displayPercentage} {
    opacity: 1;
  }
  #{$transitionPercentage + $displayPercentage + $transitionPercentage},
  100% {
    opacity: 0;
  }
}

Comments

1

Depending on how many images you want, how long you want each image to display, and how long you want the fade transition to last, you will need different values for your keyframes each time. A helpful post on how to do it properly each time can be found here: https://www.devtwins.com/blog/css-cross-fading-images

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.