Reputation: 29
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
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;
}
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