0

How can I adjust this code so that it doesn't fade out straight away? In other words, make the image fade in, sit for a few seconds and then fade back out?

This is my code right now:

    <div id="slideshow-example" data-component="slideshow">
        <div role="list">
            <div class="slide fade">
                <img src="https://images.unsplash.com/photo-1486312338219-ce68d2c6f44d?w=752&ixid=dW5zcGxhc2guY29tOzs7Ozs%3D" alt="">
            </div>
            <div class="slide fade">
                <img src="https://images.unsplash.com/photo-1488590528505-98d2b5aba04b?w=750&ixid=dW5zcGxhc2guY29tOzs7Ozs%3D" alt="">
            </div>
            <div class="slide fade">
                <img src="https://images.unsplash.com/photo-1498753427761-548428edfa67?w=889&ixid=dW5zcGxhc2guY29tOzs7Ozs%3D" alt="">
            </div>
        </div>
    </div>

[data-component="slideshow"] .slide {
    display: none;
  text-align: center;
}

[data-component="slideshow"] .slide.active {
    display: block;
}

.fade
{
    -webkit-animation: fadeinout 2s linear forwards;
    animation: fadeinout 2s linear forwards;
}

@-webkit-keyframes fadeinout {
    0%,100% { opacity: 0; }
    50% { opacity: 1; }
  }
  
@keyframes fadeinout {
  0%,100% { opacity: 0; }
  50% { opacity: 1; }
}

var slideshows = document.querySelectorAll('[data-component="slideshow"]');
slideshows.forEach(initSlideShow);

function initSlideShow(slideshow) {

    var slides = document.querySelectorAll(`#${slideshow.id} [role="list"] .slide`);

    var index = 0, time = 5000;
    slides[index].classList.add('active');

    setInterval( () => {
        slides[index].classList.remove('active');
        
        index++;
        if (index === slides.length) index = 0;

        slides[index].classList.add('active');

    }, time);
}

Please ignore this part, StackOverflow won't let me post because it's "mostly code" even though there's not much more of an explanation I can give towards my issue. If you are confused on my issue however, just ask me and I'll try and explain it more in-depth.

larkx
  • 71
  • 1
  • 9
  • I would recommend using the `transition` property instead of an animation for this, and using js async await syntax to control the delay / time flow with a helper function like `const wait = time => new Promise(resolve => setTimeout(resolve, time));` I can give more detail later if the current answer doesn't satisfy your use case. – async await Dec 25 '21 at 04:22
  • where would I put this in my code? – larkx Dec 25 '21 at 15:54
  • I added an answer for you, if you would like an example – async await Dec 26 '21 at 06:37

2 Answers2

0

You can change the percentage of which the element is shown something like the following:

var slideshows = document.querySelectorAll('[data-component="slideshow"]');
slideshows.forEach(initSlideShow);

function initSlideShow(slideshow) {

    var slides = document.querySelectorAll(`#${slideshow.id} [role="list"] .slide`);

    var index = 0, time = 5000;
    slides[index].classList.add('active');

    setInterval( () => {
        slides[index].classList.remove('active');
        
        index++;
        if (index === slides.length) index = 0;

        slides[index].classList.add('active');

    }, time);
}
[data-component="slideshow"] .slide {
    display: none;
  text-align: center;
}

[data-component="slideshow"] .slide.active {
    display: block;
}

.fade
{
    -webkit-animation: fadeinout 3s linear forwards;
    animation: fadeinout 2s linear forwards;
}

@-webkit-keyframes fadeinout {
    0%,100% { opacity: 0; }
    20%, 80% { opacity: 1; }
  }
  
@keyframes fadeinout {
  0%,100% { opacity: 0; }
  20%,50% { opacity: 1; }
}
    <div id="slideshow-example" data-component="slideshow">
        <div role="list">
            <div class="slide fade">
                <img src="https://images.unsplash.com/photo-1486312338219-ce68d2c6f44d?w=752&ixid=dW5zcGxhc2guY29tOzs7Ozs%3D" alt="">
            </div>
            <div class="slide fade">
                <img src="https://images.unsplash.com/photo-1488590528505-98d2b5aba04b?w=750&ixid=dW5zcGxhc2guY29tOzs7Ozs%3D" alt="">
            </div>
            <div class="slide fade">
                <img src="https://images.unsplash.com/photo-1498753427761-548428edfa67?w=889&ixid=dW5zcGxhc2guY29tOzs7Ozs%3D" alt="">
            </div>
        </div>
    </div>
Neveen Atik
  • 141
  • 4
  • If you want the image to stay longer or want to avoid the time where the blank background is shown you can increase the duration of the animation to match the time used in setTimeout – Neveen Atik Dec 25 '21 at 04:21
0

Here is a brief re-write of your project using async await syntax and some different logic.

First, I use two helper functions. One is a signature $ function similar to jQuery, but just to shorted grabbing things from the document. I also allow another element to be passed as the parent we are selecting things from because I feel it makes the code more readable. The other is a wait function similar to Python's sleep. There are better resources for understanding promises, but in short, any function that is called async function will allow the await keyword to "wait" for a promise to resolve.

Next, I use an anonymous arrow function passed which calls the function instead of just passing the name of the function. The reason I do this is to explicitly state which arguments from the forEach method I am passing into my function. If we do not do this, the second argument slides would be passed an index which would not be intended.

Inside the function initSlideShow we check to see if slides are defined, and if not we define it. This way we dont have to use query selector to grab things each iteration, and instead can reuse the previous values on recursive calls.

we set the time we will use later

we start looping through each slide, and first add active which will change the display to block. We need to allow the dom to render the change before fading in, so we wait 10 ms. then we remove the fade class which removes the opacity 0, and the transition css makes it fade in over 1s.

We wait the amount of time specified.

We add the fade class back to the element.

We wait the animation time we remove active, which sets display to none.

After we loop through all the slides, we just call the function again passing the slides we already fetched to do it again. A nice little recursive logic to loop the function forever.

If you have any questions regarding the code, please ask.

const $ = (str, dom = document) => [...dom.querySelectorAll(str)];
const wait = t => new Promise(r => setTimeout(r, t));

const slideshows = $('[data-component="slideshow"]');
slideshows.forEach(el => initSlideShow(el));

async function initSlideShow(container, slides) {
  if (slides == undefined) slides = $('[role="list"] .slide', container);
  const time = 5000;
  
  for (const slide of slides) {
    slide.classList.add("active");
    await wait(10);
    slide.classList.remove("fade");
    await wait(time);
    slide.classList.add("fade");
    await wait(1000);
    slide.classList.remove("active");
  }
  initSlideShow(container, slides);
}
[data-component="slideshow"] .slide {
    display: none;
    text-align: center;
    transition: opacity 1s;
}

[data-component="slideshow"] .slide.active {
    display: block;
}

.fade {
  opacity: 0;
}
<div id="slideshow-example" data-component="slideshow">
    <div role="list">
        <div class="slide fade">
            <img src="https://images.unsplash.com/photo-1486312338219-ce68d2c6f44d?w=752&ixid=dW5zcGxhc2guY29tOzs7Ozs%3D" alt="">
        </div>
        <div class="slide fade">
            <img src="https://images.unsplash.com/photo-1488590528505-98d2b5aba04b?w=750&ixid=dW5zcGxhc2guY29tOzs7Ozs%3D" alt="">
        </div>
        <div class="slide fade">
            <img src="https://images.unsplash.com/photo-1498753427761-548428edfa67?w=889&ixid=dW5zcGxhc2guY29tOzs7Ozs%3D" alt="">
        </div>
    </div>
</div>

There are many things I would do differently in an actual production app though. Changing display none to block frequently like this will likely shift the layout of the page unpredictable. I would stick to changing opacity and transition mainly. Maybe sliding the elements inside a container with hidden overflow when faded out.

async await
  • 1,967
  • 1
  • 8
  • 19