MrMerrick MrMerrick - 10 days ago 4
CSS Question

Crossfade slideshow with vanilla js between layers of separate containers

I have this code:

var current = 0,
slides = document.getElementsByClassName("slider");

setInterval(function() {
for (var i = 0; i < slides.length; i++) {
slides[i].style.opacity = 0;
}
current = (current != slides.length - 1) ? current + 1 : 0;
slides[current].style.opacity = 1;
}, 4000);


which basically iterates through my HTML making a crossfade between every layer with a "slider" class, in order: slides[0], slides1, etc, with a pause of 4 seconds between each crossfade. And then cycles from the beginning.

Now I want to expand this function to apply to 3 different containers, each with a varying number of layers inside, and I want the 3 crossfades to start at the same time and run non sequentially. By this I mean that I don't want it to go like this:

group01[0] -> group01[1] -> group01[2] -> group02[0] -> group02[1] -> group02[2]


I want it to go like this:

group01[0] -> group01[1] -> group01[2]
group02[0] -> group02[1] -> group02[2] -> group02[3]
group03[0] -> group03[1]


(so, all start at the same time, some containers have more layers than others - and then cycle from the beginning)

I tried turning the code into a reusable function where I give the layer group as an argument, but had no luck and the console doesn't throw any error:

var group01 = document.getElementById("group01").getElementsByClassName("slider");
var group02 = document.getElementById("group02").getElementsByClassName("slider");
var group03 = document.getElementById("group03").getElementsByClassName("slider");

var timer01 = setInterval(doSlider(group01), 4000);
var timer02 = setInterval(doSlider(group02), 4000);
var timer03 = setInterval(doSlider(group03), 4000);

function doSlider(slides) {
var current = 0;
for (var i = 0; i < slides.length; i++) {
slides[i].style.opacity = 0;
}
current = (current != slides.length - 1) ? current + 1 : 0;
slides[current].style.opacity = 1;
};


What am I doing wrong?

EDIT - Complete code (Pen here!: https://codepen.io/mrmerrick/pen/NbwgYo)

HTML

<div class="wrapper">

<div id="group01" class="sliderWrapper">
<div class="slider slider01">
</div>
<div class="slider slider02">
</div>
<div class="slider slider03">
</div>
<div class="slider slider04">
</div>
<img src="https://i.imgur.com/3L2LSoT.png" alt="transparent placeholder">
</div>

<div id="group02" class="sliderWrapper">
<div class="slider slider01">
</div>
<div class="slider slider02">
</div>
<div class="slider slider03">
</div>
<img src="https://i.imgur.com/3L2LSoT.png" alt="transparent placeholder">
</div>

<div id="group03" class="sliderWrapper">
<div class="slider slider01">
</div>
<div class="slider slider02">
</div>
<div class="slider slider03">
</div>
<img src="https://i.imgur.com/3L2LSoT.png" alt="transparent placeholder">
</div>

</div>


CSS

body {
margin: 0;
width: 100%;
}


.wrapper {
display: flex;
flex-direction: row;
flex-wrap: no-wrap;
height: 100vh;
}

.sliderWrapper {
position: relative;
width: 90%;
height: auto;
text-align: center;
}

.sliderWrapper img {
width: 100%;
}

.slider {
position: absolute;

top: 0;
left: 0;
width: 100%;
height: 100%;

transition: opacity .5s ease-in;
}

.slider + .slider {
opacity: 0;
}

#group01 .slider01 {
background: url(http://placehold.it/792x1599?text=group01+slide01) center center no-repeat;
background-size: contain;
z-index: 5;
}

#group01 .slider02 {
background: url(http://placehold.it/792x1599?text=group01+slide02) center center no-repeat;
background-size: contain;
z-index: 6;
}

#group01 .slider03 {
background: url(http://placehold.it/792x1599?text=group01+slide03) center center no-repeat;
background-size: contain;
z-index: 7;
}

#group01 .slider04 {
background: url(http://placehold.it/792x1599?text=group01+slide04) center center no-repeat;
background-size: contain;
z-index: 8;
}

#group02 .slider01 {
background: url(http://placehold.it/792x1599?text=group02+slide01) center center no-repeat;
background-size: contain;
z-index: 9;
}

#group02 .slider02 {
background: url(http://placehold.it/792x1599?text=group02+slide02) center center no-repeat;
background-size: contain;
z-index: 10;
}

#group02 .slider03 {
background: url(http://placehold.it/792x1599?text=group02+slide03) center center no-repeat;
background-size: contain;
z-index: 11;
}


#group03 .slider01 {
background: url(http://placehold.it/792x1599?text=group03+slide01) center center no-repeat;
background-size: contain;
z-index: 12;
}

#group03 .slider02 {
background: url(http://placehold.it/792x1599?text=group03+slide02) center center no-repeat;
background-size: contain;
z-index: 13;
}

#group03 .slider03 {
background: url(http://placehold.it/792x1599?text=group03+slide03) center center no-repeat;
background-size: contain;
z-index: 14;
}


JS

var group01 = document.getElementById("group01").getElementsByClassName("slider");
var group02 = document.getElementById("group02").getElementsByClassName("slider");
var group03 = document.getElementById("group03").getElementsByClassName("slider");

var timer01 = setInterval(doSlider(group01), 4000);
var timer02 = setInterval(doSlider(group02), 4000);
var timer03 = setInterval(doSlider(group03), 4000);

function doSlider(slides) {
var current = 0;
for (var i = 0; i < slides.length; i++) {
slides[i].style.opacity = 0;
}
current = (current != slides.length - 1) ? current + 1 : 0;
slides[current].style.opacity = 1;
};

Answer

You are setting current to 0 every time setInterval calls doSlider, which means you will only ever see slides[1]. You should close over current and slides and then increment current every time it is called by setInterval. Like so:

var group01 = document.getElementById("section01").getElementsByClassName("slider");
var group02 = document.getElementById("section02").getElementsByClassName("slider");
var group03 = document.getElementById("section03").getElementsByClassName("slider");

var slider01 = doSlider(group01);
var slider02 = doSlider(group02);
var slider03 = doSlider(group03);

var timer01 = setInterval(slider01.next, 4000);
var timer02 = setInterval(slider02.next, 4000);
var timer03 = setInterval(slider03.next, 4000);

function doSlider(slides) {
  var current = 0;
  slides[0].style.opacity = 1;
  for (var i = 1; i < slides.length; i++) {
    slides[i].style.opacity = 0;
  }
  return {
    next: function() {
      slides[current].style.opacity = 0;
      current = (current != slides.length - 1) ? current + 1 : 0;
      slides[current].style.opacity = 1;
    }
  };
}

(Hopefully this works or at least leads you to the right answer. I didn't test it).