1

As per the title, I am trying to create a JS script that cycles through a series of images in the same <div>. The images will be cycled through to create a smooth animation. So far, I have this. The images cycle through but without a smooth transition.

var slideIndex = 0;

showSlides();

function showSlides() {
  var i;
  var slides = document.getElementsByClassName("mySlides");
  
  for (i = 0; i < slides.length; i++) {
    slides[i].style.display = "none";
    slides[i].style.opacity = "0";
  }
  
  slideIndex++;
  
  if (slideIndex > slides.length) {
    slideIndex = 1
  }
  
  slides[slideIndex - 1].style.display = "block";
  slides[slideIndex - 1].style.opacity = "1";
  setTimeout(showSlides, 2500);
  // Add a transition to the images.
  slides[slideIndex - 1].style.transition = "all 2.50s";
  // Add a delay to the images.
  slides[slideIndex - 1].style.transitionDelay = "2.50s";
}
<div class="p-centered">
  <img src="https://picsum.photos/200?1" class="img-responsive mySlides" alt="">
  <img src="https://picsum.photos/200?2" class="img-responsive mySlides" alt="">
  <img src="https://picsum.photos/200?3" class="img-responsive mySlides" alt="">
  <img src="https://picsum.photos/200?4" class="img-responsive mySlides" alt="">
  <img src="https://picsum.photos/200?5" class="img-responsive mySlides" alt="">
</div>
Sebastian Simon
  • 18,263
  • 7
  • 55
  • 75
Doriandarko
  • 31
  • 1
  • 7
  • Please see [Transitions on the CSS display property](/q/3331353/4642212) and the [documentation on the `display` property](//developer.mozilla.org/en/docs/Web/CSS/display). `display` is _not animatable_, so no transition will ever be smooth when `display` is changed. See [Cross-Fade between images with CSS in loop](/a/17976033/4642212) for some working code. – Sebastian Simon Nov 22 '22 at 19:43

3 Answers3

2

Updated to have correct pointer-events behavior

Here is an example uses display: grid to place the images in stack.

It keeps the basic structure of the original code, but moves some static styling to CSS to keep the JavaScript code more focused.

Hope it will help!

Example:

var slideIndex = 0;
var slides = document.getElementsByClassName("mySlides");

// Moved some static styles to CSS to keep it clean here
showSlides();

function showSlides() {
  // Show the current image
  slides[slideIndex].classList.add("active");     
  // Hide the previous image
  const prevIndex = slideIndex === 0 ? slides.length - 1 : slideIndex - 1;
  slides[prevIndex].classList.remove("active");
  // Add index for next cycle
  slideIndex === slides.length - 1 ? (slideIndex = 0) : slideIndex++;
  // Set delay for next cycle
  setTimeout(showSlides, 2500);
}
.p-centered {
  display: grid;
  width: fit-content;
}

.mySlides {
  grid-area: 1/ 1/ 1 /1;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.50s linear;
}

.active {
  opacity: 1;
  pointer-events: auto;
}
<div class="p-centered">
  <img src="https://picsum.photos/200?1" class="img-responsive mySlides" alt="">
  <img src="https://picsum.photos/200?2" class="img-responsive mySlides" alt="">
  <img src="https://picsum.photos/200?3" class="img-responsive mySlides" alt="">
  <img src="https://picsum.photos/200?4" class="img-responsive mySlides" alt="">
  <img src="https://picsum.photos/200?5" class="img-responsive mySlides" alt="">
</div>
John Li
  • 6,976
  • 3
  • 3
  • 27
  • 1
    If an image gets opacity 0, from a UX perspective (the user wanting to drag an image to desktop) - you should also set `pointer-events: none;` or `auto` otherwise. – Roko C. Buljan Nov 22 '22 at 20:56
  • 1
    @RokoC.Buljan Makes sense! I added `pointer-events: none` and also specified `transition` for only `opacity` in this use case for safety. Thanks for the tip! – John Li Nov 22 '22 at 21:09
  • 1
    Amm, you're not setting pointer-events back to `auto` for the *active* slide item. What I meant was something more like this [jsFiddle example](https://jsfiddle.net/RokoCB/js5qwzLo/1/) - which is by all means quite more reusable. – Roko C. Buljan Nov 23 '22 at 00:36
  • @Roko Yes, I wasn't sure if it was okay to add it back to `auto` when the transition is also happening, but it turns out to be all good! I've corrected it in the code following your advice. Thanks for the example and advice! – John Li Nov 23 '22 at 00:51
  • Thanks for the pro tip on using `display: grid` to automatically size overlapping images! Much nicer than my solution. – edemaine Nov 23 '22 at 16:07
1

I think the standard way to solve this problem is to keep all images display: block, and just change opacity so that you can fade it continuously. (Alternatively, you could set display: none to images once they are completed faded out.)

For this to work, you need the images to render on top of each other. This is possible via position: absolute, provided you can size your containing element (your p-centered div) manually. For example:

let slideIndex = 0;

function showSlides() {
  const slides = document.getElementsByClassName("slide");
  // Hide existing shown slides
  for (let i = 0; i < slides.length; i++) {
    slides[i].classList.remove('show');
  }
  // Show current slide
  slides[slideIndex % slides.length].classList.add('show');
  slideIndex++;
  setTimeout(showSlides, 2500);
}

window.addEventListener('load', showSlides);
.container {
  height: 274px; /* maximum image height */
}

.slide {
  position: absolute;
  opacity: 0; /* hide until `show` class */
  transition: opacity 0.5s;
}
.slide.show {
  opacity: 1;
}
<h1>Before Container</h1>

<div class="container">
  <img class="slide" src="https://www.wikipedia.org/portal/wikipedia.org/assets/img/Wikipedia-logo-v2@1.5x.png">
  <img class="slide" src="https://www.wikiversity.org/portal/wikiversity.org/assets/img/Wikiversity-logo-tiles_1.5x.png">
</div>

<h1>After Container</h1>
edemaine
  • 2,699
  • 11
  • 20
1

You just need one class which uses the Opacity & Transition.

Activate the Class using JavaScript.

I also updated your JS code a bit so, now you don't have to iterate through all the images every time to hide them.

var slides = document.getElementsByClassName("mySlides");
var slideIndex = 0;

// Sow the First Image Initially
slides[0].classList.add("show");

setInterval(showSlides, 2500);

function showSlides() {
  // Hide Current
  slides[slideIndex].classList.remove("show");

  // Change Index
  slideIndex++;
  if (slideIndex >= slides.length) {
    slideIndex = 0
  }
  
  // Show New Current
  slides[slideIndex].classList.add("show");
}
.p-centered {
  position: relative;
}

.mySlides {
  position: absolute;
  top: 0;
  left: 0;
  opacity: 0;
  transition: all 2000ms;
}

.mySlides.show {
  opacity: 1;
}
<div class="p-centered">
  <img src="https://picsum.photos/200?1" class="img-responsive mySlides" alt="">
  <img src="https://picsum.photos/200?2" class="img-responsive mySlides" alt="">
  <img src="https://picsum.photos/200?3" class="img-responsive mySlides" alt="">
  <img src="https://picsum.photos/200?4" class="img-responsive mySlides" alt="">
  <img src="https://picsum.photos/200?5" class="img-responsive mySlides" alt="">
</div>
Shivangam Soni
  • 712
  • 5
  • 16