Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pure CSS crossfade gallery with any number of pictures

Tags:

css

I have a slideshow where pictures crossfade automatically in a loop. It is set so that 3 pictures are scrolling.

Demo in Codepen (http://codepen.io/lopis/pen/VYRoKE)

<section class="crossfade">
  <article class="slide">
    <img src="http://lorempixel.com/400/200/people" alt="" />
  </article>
  <article class="slide">
    <img src="http://lorempixel.com/400/200/cats" alt="" />
  </article>
  <article class="slide">
    <img src="http://lorempixel.com/400/200/sports" alt="" />
  </article>
</section>

The CSS:

$slideDuration: 4; // seconds
$slideNum: 3;

@mixin loop($name, $duration, $delay) {
  -webkit-animation: $name #{$duration}s #{$delay}s infinite;
  -moz-animation: $name #{$duration}s #{$delay}s infinite;
  animation: $name #{$duration}s #{$delay}s infinite;
}

@mixin slide() {
  @for $i from 1 through $slideNum {
    .slide:nth-child( #{$i} ) {
      @include loop( crossfade, ($slideNum * $slideDuration), (($i - 1) * $slideDuration) );
    }
  }
}

@mixin keyframes() {

  @-webkit-keyframes crossfade {
    0% {
      opacity:1;
    }
    25% {
      opacity:1;
    }
    33% {
      opacity:0;
    }
    86% {
      opacity:0;
    }
    100% {
      opacity:1;
    }
  }

  @keyframes crossfade {
    0% {
      opacity:1;
    }
    25% {
      opacity:1;
    }
    33% {
      opacity:0;
    }
    86% {
      opacity:0;
    }
    100% {
      opacity:1;
    }
  }
}


.crossfade {
  position: relative;
}
.slide {
  position: absolute;
  top: 0;
}
.slide:first-child {
  position: static;
}

@include slide();

@include keyframes();

Is there a way to make an animation like this that would work with any number of slides using just CSS?

Edit: I understand that such dynamism is not intended in CSS but you can have some dynamic content, like by using calc(), etc.

Some libraries, as the one suggested in the comments, allow the use of mixins for this task. This is not what I'm looking for as it requires a rebuild of the source.

like image 309
ecc Avatar asked Dec 19 '22 05:12

ecc


1 Answers

You can get this using only CSS, using a content responsive technique

Let's set a time for each slide of 2 seconds.

We need to set a staggered delay for every nth child of 2 seconds. That is easily acieved with nth-child.

Now, we need to increase the duration of the transition depending on the number of elements. Using this technique we achieve this easily.

The third issue is managing the fade-out. In the standard approach, that would involve changing the keyframes changing point, and it would be cumbersome. The trick to get this working with much less code, is to make a z-index movement in the animation itself. The elements are moving backward, and then we don't care about their opacity anymore

Example set only for 3 posible number of elements:

.container {
  width: 100px;
  height: 50px;
  position: relative;
  margin: 10px;
  display: inline-block;
}

.element {
  position: absolute;
  width: 100%;
  height: 100%;
  opacity: 0;
  animation: anim 6s infinite;
}


.element:nth-child(1) {
  background-color: lightyellow;
  animation-delay: 0s;
}

.element:nth-child(2) {
  background-color: lightgreen;
  animation-delay: 2s;
}
.element:nth-child(3) {
  background-color: pink;
  animation-delay: 4s;
}
.element:nth-child(4) {
  background-color: lightblue;
  animation-delay: 6s;
}
.element:nth-child(5) {
  background-color: coral;
  animation-delay: 8s;
}
.element:nth-child(6) {
  background-color: aliceblue;
  animation-delay: 10s;
}
.element:nth-child(7) {
  background-color: burlywood;
  animation-delay: 12s;
}
.element:nth-child(8) {
  background-color: bisque;
  animation-delay: 14s;
}
.element:nth-child(9) {
  background-color: beige;
  animation-delay: 16s;
}

.element:nth-last-child(3):first-child, 
.element:nth-last-child(3):first-child ~ .element {
  animation-duration: 6s;
}

.element:nth-last-child(6):first-child, 
.element:nth-last-child(6):first-child ~ .element {
  animation-duration: 12s;
}

.element:nth-last-child(9):first-child, 
.element:nth-last-child(9):first-child ~ .element {
  animation-duration: 18s;
}

@keyframes anim {
  0% { opacity: 0; z-index: 100;}
  15% { opacity: 1;}
  50% { opacity: 1;}
  100% { opacity: 0; z-index: 1;}
}
<div class="container">
    <div class="element">ONE</div>
    <div class="element">TWO</div>
    <div class="element">THREE</div>
</div>
<div class="container">
    <div class="element">ONE</div>
    <div class="element">TWO</div>
    <div class="element">THREE</div>
    <div class="element">FOUR</div>
    <div class="element">FIVE</div>
    <div class="element">SIX</div>
</div>
<div class="container">
    <div class="element">ONE</div>
    <div class="element">TWO</div>
    <div class="element">THREE</div>
    <div class="element">FOUR</div>
    <div class="element">FIVE</div>
    <div class="element">SIX</div>
    <div class="element">SEVEN</div>
    <div class="element">EIGHT</div>
    <div class="element">NINE</div>
</div>
like image 97
vals Avatar answered Jan 12 '23 09:01

vals