I have an image slider
with 4 images. To navigate between them there are 2 ways: 2 buttons in the corners of the slider and a small slider indicator to choose an image represented as dots in the bottom of the slider.
Each slider has a transition
property of 0.6s as follows :
.carousel-inner > .item {
background-size: cover;
background-repeat: no-repeat;
height: 470px;
position: relative;
display: none;
-webkit-transition: .6s ease-in-out left;
transition: .6s ease-in-out left;
}
What I would like to do is navigate between these images smoothly with a transition
effect, so if I choose an image that is located after the selected one both will move to the left and if the image is in the is before the selected one both the imager move to the right.
The effect that I am looking for is precisely like this one.
let slideIndex = 1;
console.log("fdsf");
function showSlide(n) {
let slides = document.querySelectorAll(".carousel-inner > .item");
let dots = document.querySelectorAll(".carousel-indicators li");
dots[slideIndex - 1].classList.remove("active");
if (n > slides.length) {
slideIndex = 1;
} else if (n < 1) {
slideIndex = slides.length;
} else {
slideIndex = n;
}
const activeSlide = document.querySelector(".carousel-inner > .item.active");
activeSlide.classList.add("left");
activeSlide.classList.remove("active");
slides[slideIndex - 1].style.left = "100%";
slides[slideIndex - 1].classList.add("active");
slides[slideIndex - 1].classList.add("left");
slides[slideIndex - 1].classList.add("next");
slides[slideIndex - 1].classList.add("left");
activeSlide.classList.remove("active");
activeSlide.classList.remove("left");
slides[slideIndex - 1].classList.remove("next");
slides[slideIndex - 1].classList.add("active");
slides[slideIndex - 1].classList.remove("left");
dots[slideIndex - 1].classList.add("active");
}
$(".carousel-indicators li").on("click", function () {
showSlide(parseInt(this.getAttribute("data-slide-to")) + 1)
})
.carousel {
position: relative;
}
@media screen and (min-width: 768px) {
.carousel-indicators {
bottom: 20px;
}
}
.carousel-indicators {
position: absolute;
bottom: 10px;
left: 50%;
z-index: 15;
width: 60%;
padding-left: 0;
margin-left: -30%;
text-align: center;
list-style: none;
}
ul, ol {
margin-top: 0;
margin-bottom: 10px;
}
.carousel-indicators li {
display: inline-block;
width: 10px;
height: 10px;
margin: 1px;
text-indent: -999px;
cursor: pointer;
background-color: #000 9;
background-color: rgba(0, 0, 0, 0);
border: 1px solid #fff;
border-radius: 10px;
}
.carousel-indicators .active {
width: 12px;
height: 12px;
margin: 0;
background-color: #fff;
}
.carousel-inner {
position: relative;
width: 100%;
overflow: hidden;
}
.carousel-inner > .item.slide1 {
background-position: center 10%;
}
.carousel-inner > .item {
background-size: cover;
background-repeat: no-repeat;
height: 470px;
position: relative;
display: none;
-webkit-transition: .6s ease-in-out left;
transition: .6s ease-in-out left;
}
.carousel-inner > .next, .carousel-inner > .prev {
position: absolute;
top: 0;
width: 100%
}
.carousel-inner > .next {
left: 100%
}
.carousel-inner > .prev {
left: -100%
}
.carousel-inner > .next.left, .carousel-inner > .prev.right {
left: 0
}
.carousel-inner > .active.left {
left: -100%
}
.carousel-inner > .active.right {
left: 100%
}
.carousel-inner > .active {
left: 0;
}
.carousel-inner > .active, .carousel-inner > .next, .carousel-inner > .prev {
display: block;
}
.carousel-control.left {
background-image: -webkit-gradient(linear, 0 top, 100% top, from(rgba(0, 0, 0, 0.5)), to(rgba(0, 0, 0, 0.0001)));
background-image: -webkit-linear-gradient(left, color-stop(rgba(0, 0, 0, 0.5) 0), color-stop(rgba(0, 0, 0, 0.0001) 100%));
background-image: -moz-linear-gradient(left, rgba(0, 0, 0, 0.5) 0, rgba(0, 0, 0, 0.0001) 100%);
background-image: linear-gradient(to right, rgba(0, 0, 0, 0.5) 0, rgba(0, 0, 0, 0.0001) 100%);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);
}
.carousel-control.right {
right: 0;
left: auto;
background-image: -webkit-gradient(linear, 0 top, 100% top, from(rgba(0, 0, 0, 0.0001)), to(rgba(0, 0, 0, 0.5)));
background-image: -webkit-linear-gradient(left, color-stop(rgba(0, 0, 0, 0.0001) 0), color-stop(rgba(0, 0, 0, 0.5) 100%));
background-image: -moz-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0, rgba(0, 0, 0, 0.5) 100%);
background-image: linear-gradient(to right, rgba(0, 0, 0, 0.0001) 0, rgba(0, 0, 0, 0.5) 100%);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);
}
.carousel-control {
position: absolute;
top: 0;
bottom: 0;
left: 0;
width: 15%;
font-size: 20px;
color: #fff;
text-align: center;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
opacity: .5;
filter: alpha(opacity=50);
}
.carousel-control .icon-prev, .carousel-control .glyphicon-chevron-left {
left: 50%;
}
.carousel-control .icon-prev, .carousel-control .icon-next, .carousel-control .glyphicon-chevron-left, .carousel-control .glyphicon-chevron-right {
position: absolute;
top: 50%;
z-index: 5;
display: inline-block;
}
.glyphicon-chevron-left::before {
content: url(../images/icons/left-arrow.png);
border-radius: 50%;
border: 1px solid white;
display: block;
width: 100%;
height: 100%;
background-repeat: no-repeat;
background-position: center;
background-size: contain;
}
.carousel-control .icon-next, .carousel-control .glyphicon-chevron-right {
right: 50%;
}
.carousel-control .icon-prev, .carousel-control .icon-next, .carousel-control .glyphicon-chevron-left, .carousel-control .glyphicon-chevron-right {
position: absolute;
top: 50%;
z-index: 5;
display: inline-block;
}
.glyphicon:empty {
width: 1em;
}
.glyphicon-chevron-right::before {
content: url(../images/icons/right-arrow.png);
border-radius: 50%;
border: 1px solid white;
display: block;
width: 100%;
height: 100%;
background-repeat: no-repeat;
background-position: center;
background-size: contain;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script src="https://code.jquery.com/jquery-3.7.0.min.js" integrity="sha256-2Pmvv0kuTBOenSvLm6bvfBSSHrUJ+3A7x6P5Ebd07/g=" crossorigin="anonymous"></script>
<title>Document</title>
</head>
<body>
<div id="myCarousel" class="carousel slide" data-ride="carousel">
<ol class="carousel-indicators">
<li data-target="#myCarousel" data-slide-to="0" class="active"></li>
<li data-target="#myCarousel" data-slide-to="1" class=""></li>
<li data-target="#myCarousel" data-slide-to="2" class=""></li>
<li data-target="#myCarousel" data-slide-to="3" class=""></li>
</ol>
<div class="carousel-inner">
<div
class="item slide1 active"
style="
background-image: url(https://upload.wikimedia.org/wikipedia/commons/1/15/Cat_August_2010-4.jpg);
background-size: cover;
background-repeat: no-repeat;
"
>
<div id="page-header-tagline" class="tagline1"></div>
</div>
<div
class="item slide2"
style="
background-image: url(https://static.toiimg.com/thumb/msid-67586673,width-1070,height-580,imgsize-3918697,resizemode-6,overlay-toi_sw,pt-32,y_pad-40/photo.jpg);
background-size: cover;
background-repeat: no-repeat;
"
>
<div id="page-header-tagline" class="tagline2"></div>
</div>
<div
class="item slide3"
style="
background-image: url(https://upload.wikimedia.org/wikipedia/commons/1/15/Cat_August_2010-4.jpg);
background-size: cover;
background-repeat: no-repeat;
"
>
<div id="page-header-tagline" class="tagline3"></div>
</div>
<div
class="item slide4"
style="
background-image: url(https://static.toiimg.com/thumb/msid-67586673,width-1070,height-580,imgsize-3918697,resizemode-6,overlay-toi_sw,pt-32,y_pad-40/photo.jpg);
background-size: cover;
background-repeat: no-repeat;
"
>
<div id="page-header-tagline" class="tagline4"></div>
</div>
</div>
<a class="carousel-control left" href="#myCarousel" data-slide="prev">
<span class="glyphicon glyphicon-chevron-left"></span>
</a>
<a class="carousel-control right" href="#myCarousel" data-slide="next">
<span class="glyphicon glyphicon-chevron-right"></span>
</a>
</div>
</body>
</html>
2
Answers
I solved the issue by updating the function
showSlide
, by changing the order and the way theclasses
' names are being removed and added to elements of thetransition
when changing the slide, I also usedsettimeout
function since the operation must be divided into steps :next
to the element we want to show, update itsdisplay
, andrender
it into the dom.timeout
is responsible for adding the classleft
for both elements. That class is responsible for shifting both the images (old and new) to theleft
by 100% (the shift will no happen immediately since the element with the classnext
andleft
has a left of 0)timeout
will be responsible for the final updates and it will update both the elements by adding and removing their final classes.Here is how it looks now :
Instead of using
setTimeout
, userequestAnimationFrame
. More specifically a doublerequestAnimationFrame
which enables us to wait for the browser to paint the next frame and do something after that happens. This way you don’t have to guess the time to wait untildisplay: block
has been painted by the browser.Same goes for the second timeout, but there you want to do something after the transition has finished. You can accomplish this more accurately by listening to the transitionend event. And to make sure that the event is only listened to once per slide change, add
{ once: true }
as options param toaddEventListener
.I took the liberty to add a flag
isAnimating
to the slider to indicate that the slider is moving and nothing should happen until the animation is finished.