Chris
Chris

Reputation: 29

How do I prevent white flash between images?

enter image description here

enter image description here

I'd like the current image to fade out at the same time that the next image fades in (like the second image above), with no white flash in between. I feel like it has something to do with the javascript, but I can't detect what's wrong. Any advice?

Here's the component code:

const ImageSlider = ({ slides }) => {
  const [current, setCurrent] = useState(0);
  const length = slides.length;

  const nextSlide = () => {
    setCurrent(current === length - 1 ? 0 : current + 1);
  };

  const prevSlide = () => {
    setCurrent(current === 0 ? length - 1 : current - 1);
  };

  if (!Array.isArray(slides) || slides.length <= 0) {
    return null;
  }

  return (
    <section className="slider">
      <FaArrowAltCircleLeft className="left-arrow" onClick={prevSlide} />
      {SliderData.map((slide, index) => {
        return (
          <div
            className={index === current ? "slide active" : "slide"}
            key={slide.id}
          >
            {index === current && (
              <img src={slide.img} alt="" className="image" />
            )}
          </div>
        );
      })}
      <FaArrowAltCircleRight className="right-arrow" onClick={nextSlide} />
    </section>
  );
};

export default ImageSlider;

And the css:

.slider {
  position: relative;
  height: 90vh;
}

.image {
  width: 100vw;
  height: 100vh;
  object-fit: cover;
  object-position: center;
}
.slide {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: 200ms opacity ease-in-out;
  transition-delay: 200ms;
}

.slide.active {
  opacity: 1;
  z-index: 1;
  transition-delay: 0ms;
}
.slide > img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;

Upvotes: 1

Views: 617

Answers (1)

Tushar Shahi
Tushar Shahi

Reputation: 20616

EDIT:

The OP wanted both the images to have a an animation. But this is currently not possible. Why?

Because of this statement:

            {index === current && (
              <img src={slide.img} alt="" className="image" />
            )}

There is only one image to be shown at a time. The one whose index is matching with current. So there is only one image in the DOM. There is no chance of having one image fade in while the other fades out.

To achieve something like that I would prefer having two images in the DOM at the same time. One current and one previous.

We keep updating the previous value into another state variable.

const ImageSlider = ({ slides }) => {
  const [current, setCurrent] = useState(0);
  const [prevCurrent, setPrevCurrent] = useState(-1);
  const length = SliderData.length;

  const nextSlide = () => {
    setPrevCurrent(current);
    setCurrent(current === length - 1 ? 0 : current + 1);
  };

  const prevSlide = () => {
    setPrevCurrent(current);
    setCurrent(current === 0 ? length - 1 : current - 1);
  };

  if (!Array.isArray(SliderData) || SliderData.length <= 0) {
    return null;
  }

  return (
    <section className="slider">
      <button className="left-arrow" onClick={nextSlide}>
        Left
      </button>
      {SliderData.map((slide, index) => {
        return (
          <div
            className={index === current ? "slide active" : "slide hide"}
            key={slide.id}
          >
            {index === current && (
              <img src={slide.img} alt="" className="image" />
            )}
            {prevCurrent > -1 && index === prevCurrent && (
              <img src={slide.img} alt="" className="image" />
            )}
          </div>
        );
      })}
      <button className="right-arrow" onClick={prevSlide}>
        Right
      </button>
    </section>
  );
};

Updated the css to something like this. Having the hide and active classes separate can help you easily use this somewhere else too.

.slide {
  position: absolute;
  inset: 0;
}

.active {
  opacity: 1;
  transition: opacity 4s ease-in-out;
}
.hide {
  opacity: 0;
  transition: opacity 4s ease-in-out;
}

Updated Link Demo

Earlier it was assumed that the fade effect was required only for one image. Without changing the JS code, it could be achieved like this:

PREVIOUS:

Changed your css to this and it worked:

.slide {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 1s ease-in-out;
}

.slide.active {
  opacity: 1;
}

If we keep a transition delay in .active which is much higher than the one in non-active state, then we will see a blank screen. So removed that too.

Here is a sandbox link of my fix. I had to increase the duration a bit so I could notice the effect. You can tweak around to see your desired effect, like a delay of 3s is really peaceful.

Upvotes: 1

Related Questions