Slideshow with different amount of images per slide - javascript

I'm trying to do a slideshow. A normal slideshow has one image per slide, but in my case every slide has different amount of images.
Here is an example of 2 slides:
First Slide
Second Slide
I've working fine with one image, but can't put with more than that per page.
let currentSlide = 0;
const slides = document.querySelectorAll(".slide")
const dots = document.querySelectorAll('.dot')
const init = (n) => {
slides.forEach((slide, index) => {
slide.style.display = "none"
dots.forEach((dot, index) => {
dot.classList.remove("active")
})
})
slides[n].style.display = "block"
dots[n].classList.add("active")
}
document.addEventListener("DOMContentLoaded", init(currentSlide))
const next = () => {
currentSlide >= slides.length - 1 ? currentSlide = 0 : currentSlide++
init(currentSlide)
}
const prev = () => {
currentSlide <= 0 ? currentSlide = slides.length - 1 : currentSlide--
init(currentSlide)
}
document.querySelector(".next").addEventListener('click', next)
document.querySelector(".prev").addEventListener('click', prev)
setInterval(() => {
next()
}, 5000);
dots.forEach((dot, i) => {
dot.addEventListener("click", () => {
console.log(currentSlide)
init(i)
currentSlide = i
})
})
.slide-container .prev,
.slide-container .next {
cursor: pointer;
position: absolute;
top: 50%;
width: auto;
margin-top: -22px;
padding: 16px;
color: white;
font-weight: bold;
font-size: 20px;
transition: all 0.6s ease;
border-radius: 0 3px 3px 0;
user-select: none;
}
.slide-container .prev:hover,
.slide-container .next:hover {
background-color: rgba(0, 0, 0, 0.8);
color: white;
}
.slide-container .prev {
left: 2px;
}
.slide-container .next {
right: 2px;
}
.dots-container {
display: flex;
justify-content: center;
align-items: center;
padding: 10px;
}
.dots-container .dot {
cursor: pointer;
margin: 5px;
width: 20px;
height: 20px;
color: #333;
border-radius: 50%;
background-color: #dfd6ce;
}
.dots-container .dot.active {
border: 2px solid green;
}
* {
padding: 0;
border: 0;
box-sizing: border-box;
}
body {
height: 100%;
/* background-image: linear-gradient(to top, #accbee 0%, #e7f0fd 100%); */
}
body h1 {
text-align: center;
}
.slide-container {
display: flex;
justify-content: center;
align-items: center;
max-width: 1000px;
margin: auto;
position: relative;
}
.slide-container .slide {
display: none;
width: 100%;
}
.slide-container .slide.fade {
animation: fade 0.5s cubic-bezier(0.55, 0.085, 0.68, 0.53) both;
}
.slide-container .slide img {
width: 100%;
}
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Image Slider</title>
</head>
<body>
<h1>Image Slider</h1>
<div class="slide-container">
<div class="slide fade">
<img src='https://images.unsplash.com/photo-1590595978583-3967cf17d2ea?ixlib=rb-1.2.1&q=85&fm=jpg&crop=entropy&cs=srgb&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt=''>
</div>
<div class="slide fade">
<img src='https://images.unsplash.com/photo-1588807308097-fb6e5047df8c?ixlib=rb-1.2.1&q=85&fm=jpg&crop=entropy&cs=srgb&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt=''>
</div>
<div class="slide fade">
<img src='https://images.unsplash.com/photo-1589808710416-24cf7ac026f2?ixlib=rb-1.2.1&q=85&fm=jpg&crop=entropy&cs=srgb&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt=''>
</div>
<div class="slide fade">
<img src='https://images.unsplash.com/photo-1588796388882-a4d533c47e5e?ixlib=rb-1.2.1&q=85&fm=jpg&crop=entropy&cs=srgb&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt=''>
</div>
&#10094
&#10095
</div>
<div class="dots-container">
<span class="dot"></span>
<span class="dot"></span>
<span class="dot"></span>
<span class="dot"></span>
</div>
</body>
</html>
If anyone can help, it will help a lot.
Thanks

One way of getting more than one image per slide is to put several img elements in the slide and size them accordingly.
This snippet is just basic - put two imgs into the first slide and give them 45% width each (so they have room to be next to each other).
Depending on how general you need to be you will have to do some sort of calculation for each slide which calculates the relevant width for each image in it, possibly just 100/n% of the slide's width, but maybe more complex if your images are of different aspect ratios.
let currentSlide = 0;
const slides = document.querySelectorAll(".slide")
const dots = document.querySelectorAll('.dot')
const init = (n) => {
slides.forEach((slide, index) => {
slide.style.display = "none"
dots.forEach((dot, index) => {
dot.classList.remove("active")
})
})
slides[n].style.display = "block"
dots[n].classList.add("active")
}
document.addEventListener("DOMContentLoaded", init(currentSlide))
const next = () => {
currentSlide >= slides.length - 1 ? currentSlide = 0 : currentSlide++
init(currentSlide)
}
const prev = () => {
currentSlide <= 0 ? currentSlide = slides.length - 1 : currentSlide--
init(currentSlide)
}
document.querySelector(".next").addEventListener('click', next)
document.querySelector(".prev").addEventListener('click', prev)
setInterval(() => {
next()
}, 5000);
dots.forEach((dot, i) => {
dot.addEventListener("click", () => {
console.log(currentSlide)
init(i)
currentSlide = i
})
})
.slide-container .prev,
.slide-container .next {
cursor: pointer;
position: absolute;
top: 50%;
width: auto;
margin-top: -22px;
padding: 16px;
color: white;
font-weight: bold;
font-size: 20px;
transition: all 0.6s ease;
border-radius: 0 3px 3px 0;
user-select: none;
}
.slide-container .prev:hover,
.slide-container .next:hover {
background-color: rgba(0, 0, 0, 0.8);
color: white;
}
.slide-container .prev {
left: 2px;
}
.slide-container .next {
right: 2px;
}
.dots-container {
display: flex;
justify-content: center;
align-items: center;
padding: 10px;
}
.dots-container .dot {
cursor: pointer;
margin: 5px;
width: 20px;
height: 20px;
color: #333;
border-radius: 50%;
background-color: #dfd6ce;
}
.dots-container .dot.active {
border: 2px solid green;
}
* {
padding: 0;
border: 0;
box-sizing: border-box;
}
body {
height: 100%;
/* background-image: linear-gradient(to top, #accbee 0%, #e7f0fd 100%); */
}
body h1 {
text-align: center;
}
.slide-container {
display: flex;
justify-content: center;
align-items: center;
max-width: 1000px;
margin: auto;
position: relative;
}
.slide-container .slide {
display: none;
width: 100%;
}
.slide-container .slide.fade {
animation: fade 0.5s cubic-bezier(0.55, 0.085, 0.68, 0.53) both;
}
.slide-container .slide img {
width: 100%;
}
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Image Slider</title>
</head>
<body>
<h1>Image Slider</h1>
<div class="slide-container">
<div class="slide fade">
<img src='https://images.unsplash.com/photo-1590595978583-3967cf17d2ea?ixlib=rb-1.2.1&q=85&fm=jpg&crop=entropy&cs=srgb&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='' style="width: 45%; height: auto;">
<img src='https://images.unsplash.com/photo-1588807308097-fb6e5047df8c?ixlib=rb-1.2.1&q=85&fm=jpg&crop=entropy&cs=srgb&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='' style="width: 45%; height: auto;">
</div>
<div class="slide fade">
<img src='https://images.unsplash.com/photo-1588807308097-fb6e5047df8c?ixlib=rb-1.2.1&q=85&fm=jpg&crop=entropy&cs=srgb&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt=''>
</div>
<div class="slide fade">
<img src='https://images.unsplash.com/photo-1589808710416-24cf7ac026f2?ixlib=rb-1.2.1&q=85&fm=jpg&crop=entropy&cs=srgb&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt=''>
</div>
<div class="slide fade">
<img src='https://images.unsplash.com/photo-1588796388882-a4d533c47e5e?ixlib=rb-1.2.1&q=85&fm=jpg&crop=entropy&cs=srgb&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt=''>
</div>
&#10094
&#10095
</div>
<div class="dots-container">
<span class="dot"></span>
<span class="dot"></span>
<span class="dot"></span>
<span class="dot"></span>
</div>
</body>
</html>

Related

carousel with popup when clicking on the image error

I am trying to create a image carousel and when clicking on one of the images, the exact image enlarges in a popup with a close button. Right now, i'm having this issue where when i click on the second image on the carousel, the popup comes up with the first picture on the carousel.
Here is my HTML Code
<div class="carousel">
<input class="carousel-open" type="radio" id="carousel-1" name="carousel" aria-hidden="true" hidden="" checked="checked">
<div class="carousel-item">
<img src="C:\Users\uppil\OneDrive\Desktop\WD\SS project\Used Resources\Wildlife 1.jpg" onclick="openModal();currentSlide(1)" width="351" height="256" class="hover-shadow cursor">
</div>
<input class="carousel-open" type="radio" id="carousel-2" name="carousel" aria-hidden="true" hidden="">
<div class="carousel-item">
<img src="C:\Users\uppil\OneDrive\Desktop\WD\SS project\Used Resources\Wildlife 2.jpg" onclick="openModal();currentSlide(2)" width="351" height="256" class="hover-shadow cursor">
</div>
<input class="carousel-open" type="radio" id="carousel-3" name="carousel" aria-hidden="true" hidden="">
<div class="carousel-item">
<img src="C:\Users\uppil\OneDrive\Desktop\WD\SS project\Used Resources\Wildlife 3.jpg" onclick="openModal();currentSlide(3)" width="351" height="256" class="hover-shadow cursor">
</div>
<div class="carousel-item">
<img src="C:\Users\uppil\OneDrive\Desktop\WD\SS project\Used Resources\Wildlife 4.jpg" onclick="openModal();currentSlide(4)" width="351" height="256" class="hover-shadow cursor">
</div>
<label for="carousel-3" class="carousel-control prev control-1">‹</label>
<label for="carousel-2" class="carousel-control next control-1">›</label>
<label for="carousel-1" class="carousel-control prev control-2">‹</label>
<label for="carousel-3" class="carousel-control next control-2">›</label>
<label for="carousel-2" class="carousel-control prev control-3">‹</label>
<label for="carousel-1" class="carousel-control next control-3">›</label>
<ol class="carousel-indicators">
<li>
<label for="carousel-1" class="carousel-bullet">•</label>
</li>
<li>
<label for="carousel-2" class="carousel-bullet">•</label>
</li>
<li>
<label for="carousel-3" class="carousel-bullet">•</label>
</li>
</ol>
</div>
</div>
<div id="myModal" class="modal">
<span class="close cursor" onclick="closeModal()">×</span>
<div class="modal-content">
<div class="mySlides">
<div class="numbertext">1 / 4</div>
<img src="C:\Users\uppil\OneDrive\Desktop\WD\SS project\Used Resources\Wildlife 1.jpg" style="width: 100%;">
</div>
<div class="mySlides">
<div class="numbertext">2 / 4</div>
<img src="C:\Users\uppil\OneDrive\Desktop\WD\SS project\Used Resources\Wildlife 2.jpg" style="width:100%">
</div>
<div class="mySlides">
<div class="numbertext">3 / 4</div>
<img src="C:\Users\uppil\OneDrive\Desktop\WD\SS project\Used Resources\Wildlife 3.jpg" style="width:100%">
</div>
<div class="mySlides">
<div class="numbertext">3 / 4</div>
<img src="C:\Users\uppil\OneDrive\Desktop\WD\SS project\Used Resources\Wildlife 3.jpg" style="width:100%">
</div>
<div class="mySlides">
<div class="numbertext">4 / 4</div>
<img src="C:\Users\uppil\OneDrive\Desktop\WD\SS project\Used Resources\Wildlife 4.jpg" style="width:100%">
</div>
<a class="prev" onclick="plusSlides(-1)">❮</a>
<a class="next" onclick="plusSlides(1)">❯</a>
<div class="caption-container">
<p id="caption"></p>
</div>
Here is my JavaScript Code
function openModal() {
document.getElementById("myModal").style.display = "block";
}
function closeModal() {
document.getElementById("myModal").style.display = "none";
}
var slideIndex = 1;
showSlides(slideIndex);
function plusSlides(n) {
showSlides(slideIndex += n);
}
function currentSlide(n) {
showSlides(slideIndex = n);
}
function showSlides(n) {
var i;
var slides = document.getElementsByClassName("mySlides");
var dots = document.getElementsByClassName("demo");
var captionText = document.getElementById("caption");
if (n > slides.length) {slideIndex = 1}
if (n < 1) {slideIndex = slides.length}
for (i = 0; i < slides.length; i++) {
slides[i].style.display = "none";
}
for (i = 0; i < dots.length; i++) {
dots[i].className = dots[i].className.replace(" active", "");
}
slides[slideIndex-1].style.display = "block";
dots[slideIndex-1].className += " active";
captionText.innerHTML = dots[slideIndex-1].alt;
}
$(document).ready(function() {
var sync1 = $("#sync1");
var sync2 = $("#sync2");
var slidesPerPage = 4; //globaly define number of elements per page
var syncedSecondary = true;
sync1.owlCarousel({
items : 1,
slideSpeed : 2000,
nav: true,
//autoplay: true,
dots: true,
loop: true,
responsiveRefreshRate : 200,
navText: ['<svg width="100%" height="100%" viewBox="0 0 11 20"><path style="fill:none;stroke-width: 1px;stroke: #FFF;" d="M9.554,1.001l-8.607,8.607l8.607,8.606"/></svg>','<svg width="100%" height="100%" viewBox="0 0 11 20" version="1.1"><path style="fill:none;stroke-width: 1px;stroke: #FFF;" d="M1.054,18.214l8.606,-8.606l-8.606,-8.607"/></svg>'],
}).on('changed.owl.carousel', syncPosition);
sync2
.on('initialized.owl.carousel', function () {
sync2.find(".owl-item").eq(0).addClass("current");
})
.owlCarousel({
items : slidesPerPage,
dots: true,
nav: true,
smartSpeed: 200,
slideSpeed : 500,
slideBy: slidesPerPage, //alternatively you can slide by 1, this way the active slide will stick to the first item in the second carousel
responsiveRefreshRate : 100
}).on('changed.owl.carousel', syncPosition2);
function syncPosition(el) {
//if you set loop to false, you have to restore this next line
//var current = el.item.index;
//if you disable loop you have to comment this block
var count = el.item.count-1;
var current = Math.round(el.item.index - (el.item.count/2) - .5);
if(current < 0) {
current = count;
}
if(current > count) {
current = 0;
}
//end block
sync2
.find(".owl-item")
.removeClass("current")
.eq(current)
.addClass("current");
var onscreen = sync2.find('.owl-item.active').length - 1;
var start = sync2.find('.owl-item.active').first().index();
var end = sync2.find('.owl-item.active').last().index();
if (current > end) {
sync2.data('owl.carousel').to(current, 100, true);
}
if (current < start) {
sync2.data('owl.carousel').to(current - onscreen, 100, true);
}
}
function syncPosition2(el) {
if(syncedSecondary) {
var number = el.item.index;
sync1.data('owl.carousel').to(number, 100, true);
}
}
sync2.on("click", ".owl-item", function(e){
e.preventDefault();
var number = $(this).index();
sync1.data('owl.carousel').to(number, 300, true);
});
});
$(document).ready(function() {
$('.image-popup-vertical-fit').magnificPopup({
type: 'image',
closeOnContentClick: true,
mainClass: 'mfp-img-mobile',
image: {
verticalFit: true
}
});
$('.image-popup-fit-width').magnificPopup({
type: 'image',
closeOnContentClick: true,
image: {
verticalFit: false
}
});
$('.image-popup-no-margins').magnificPopup({
type: 'image',
closeOnContentClick: true,
closeBtnInside: false,
fixedContentPos: true,
mainClass: 'mfp-no-margins mfp-with-zoom', // class to remove default margin from left and right side
image: {
verticalFit: true
},
zoom: {
enabled: true,
duration: 300 // don't foget to change the duration also in CSS
}
});
});
Here is my CSS
html, body {
margin: 0px;
padding: 0px;
background-color: black;
}
.carousel {
position: relative;
box-shadow: 0px 1px 6px rgba(0, 0, 0, 0.64);
margin-top: 26px;
}
.carousel-inner {
position: relative;
overflow: hidden;
width: 100%;
}
.carousel-open:checked + .carousel-item {
position: static;
opacity: 100;
}
.carousel-item {
position: absolute;
opacity: 0;
-webkit-transition: opacity 0.6s ease-out;
transition: opacity 0.6s ease-out;
margin-left: 800px;
}
.carousel-item img {
display: block;
height: auto;
max-width: 100%;
}
.carousel-control {
background: rgba(0, 0, 0, 0.28);
border-radius: 50%;
color: #fff;
cursor: pointer;
display: none;
font-size: 40px;
height: 40px;
line-height: 35px;
position: absolute;
top: 50%;
-webkit-transform: translate(0, -50%);
cursor: pointer;
-ms-transform: translate(0, -50%);
transform: translate(0, -50%);
text-align: center;
width: 40px;
z-index: 10;
}
.carousel-control.prev {
left: 2%;
}
.carousel-control.next {
right: 2%;
}
.carousel-control:hover {
background: rgba(0, 0, 0, 0.8);
color: #aaaaaa;
}
#carousel-1:checked ~ .control-1,
#carousel-2:checked ~ .control-2,
#carousel-3:checked ~ .control-3 {
display: block;
}
.carousel-indicators {
list-style: none;
margin: 0;
padding: 0;
position: absolute;
bottom: 2%;
left: 0;
right: 0;
text-align: center;
z-index: 10;
background-color: transparent;
}
.carousel-indicators li {
display: inline-block;
margin: 0 5px;
background-color: transparent;
}
.carousel-bullet {
color: #fff;
cursor: pointer;
display: block;
font-size: 35px;
background-color: transparent;
}
.carousel-bullet:hover {
color: #aaaaaa;
}
#carousel-1:checked ~ .control-1 ~ .carousel-indicators li:nth-child(1) .carousel-bullet,
#carousel-2:checked ~ .control-2 ~ .carousel-indicators li:nth-child(2) .carousel-bullet,
#carousel-3:checked ~ .control-3 ~ .carousel-indicators li:nth-child(3) .carousel-bullet {
color: #428bca;
}
#title {
width: 100%;
position: absolute;
padding: 0px;
margin: 0px auto;
text-align: center;
font-size: 27px;
color: rgba(255, 255, 255, 1);
font-family: 'Open Sans', sans-serif;
z-index: 9999;
text-shadow: 0px 1px 2px rgba(0, 0, 0, 0.33), -1px 0px 2px rgba(255, 255, 255, 0);
}
html, body {
margin: 0px;
padding: 0px;
background: url("http://digital.bnint.com/filelib/s9/photos/white_wood_4500x3000_lo_res.jpg");
background-color: black;
}
.carousel1 {
position: relative;
box-shadow: 0px 1px 6px rgba(0, 0, 0, 0.64);
margin-top: 26px;
}
.carousel1-inner {
position: relative;
overflow: hidden;
width: 100%;
}
.carousel1-open:checked + .carousel1-item {
position: static;
opacity: 100;
}
.carousel1-item {
position: absolute;
opacity: 0;
-webkit-transition: opacity 0.6s ease-out;
transition: opacity 0.6s ease-out;
margin-left: 800px;
}
.carousel1-item img {
display: block;
height: auto;
max-width: 100%;
}
.carousel1-control {
background: rgba(0, 0, 0, 0.28);
border-radius: 50%;
color: #fff;
cursor: pointer;
display: none;
font-size: 40px;
height: 40px;
line-height: 35px;
position: absolute;
top: 50%;
-webkit-transform: translate(0, -50%);
cursor: pointer;
-ms-transform: translate(0, -50%);
transform: translate(0, -50%);
text-align: center;
width: 40px;
z-index: 10;
}
.carousel1-control.prev {
left: 2%;
}
.carousel1-control.next {
right: 2%;
}
.carousel1-control:hover {
background: rgba(0, 0, 0, 0.8);
color: #aaaaaa;
}
#carousel1-1:checked ~ .control-1,
#carousel1-2:checked ~ .control-2,
#carousel1-3:checked ~ .control-3 {
display: block;
}
.carousel1-indicators {
list-style: none;
margin: 0;
padding: 0;
position: absolute;
bottom: 2%;
left: 0;
right: 0;
text-align: center;
z-index: 10;
background-color: transparent;
}
.carousel1-indicators li {
display: inline-block;
margin: 0 5px;
background-color: transparent;
}
.carousel1-bullet {
color: #fff;
cursor: pointer;
display: block;
font-size: 35px;
background-color: transparent;
}
.carousel1-bullet:hover {
color: #aaaaaa;
}
#carousel1-1:checked ~ .control-1 ~ .carousel1-indicators li:nth-child(1) .carousel1-bullet,
#carousel1-2:checked ~ .control-2 ~ .carousel1-indicators li:nth-child(2) .carousel1-bullet,
#carousel1-3:checked ~ .control-3 ~ .carousel1-indicators li:nth-child(3) .carousel1-bullet {
color: #428bca;
}
#title {
width: 100%;
position: absolute;
padding: 0px;
margin: 0px auto;
text-align: center;
font-size: 27px;
color: rgba(255, 255, 255, 1);
font-family: 'Open Sans', sans-serif;
z-index: 9999;
text-shadow: 0px 1px 2px rgba(0, 0, 0, 0.33), -1px 0px 2px rgba(255, 255, 255, 0);
}
body {
font-family: Verdana, sans-serif;
margin: 0;
}
* {
box-sizing: border-box;
}
.row > .column {
padding: 0 8px;
}
.row:after {
content: "";
display: table;
clear: both;
}
.column {
float: left;
width: 25%;
}
/* The Modal (background) */
.modal {
display: none;
position: fixed;
z-index: 1;
padding-top: 100px;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: black;
}
/* Modal Content */
.modal-content {
position: relative;
background-color: #fefefe;
margin: auto;
padding: 0;
width: 90%;
max-width: 1200px;
}
/* The Close Button */
.close {
color: white;
position: absolute;
top: 10px;
right: 25px;
font-size: 35px;
font-weight: bold;
}
.close:hover,
.close:focus {
color: #999;
text-decoration: none;
cursor: pointer;
}
.mySlides {
display: none;
}
.cursor {
cursor: pointer;
}
/* Next & previous buttons */
.prev,
.next {
cursor: pointer;
position: absolute;
top: 50%;
width: auto;
padding: 16px;
margin-top: -50px;
color: white;
font-weight: bold;
font-size: 20px;
transition: 0.6s ease;
border-radius: 0 3px 3px 0;
user-select: none;
-webkit-user-select: none;
}
/* Position the "next button" to the right */
.next {
right: 0;
border-radius: 3px 0 0 3px;
}
/* On hover, add a black background color with a little bit see-through */
.prev:hover,
.next:hover {
background-color: rgba(0, 0, 0, 0.8);
}
/* Number text (1/3 etc) */
.numbertext {
color: #f2f2f2;
font-size: 12px;
padding: 8px 12px;
position: absolute;
top: 0;
}
img {
margin-bottom: -4px;
}
.caption-container {
text-align: center;
background-color: black;
padding: 2px 16px;
color: white;
}
.demo {
opacity: 0.6;
}
.active,
.demo:hover {
opacity: 1;
}
img.hover-shadow {
transition: 0.3s;
}
.hover-shadow:hover {
box-shadow: 0 4px 8px 0 rgba(255, 255, 255, 0.2), 0 6px 20px 0 rgba(255, 255, 255, 0.19);
}
i have tried the code a few times and i see that at first when i click the arrow button to move to the next image, for a few millisecond the popup redirects me correctly, after that, the correct popup does not work and when i click on the image it comes up with the wrong popup.

Carousel slides appear beneath each other on click

I'm using HTML/CSS and vanilla JS. I'm trying to create a simple carousel. However, whenever I click the 'next' button, the following slides show up under the last one. I'm not sure why this is happening. Code snippets are below. Can someone explain why this is happening?
By the way, I have not optimized this page for media queries yet, so it might look a little weird on smaller screens.
const buttons = document.querySelectorAll("[data-carousel-btn]");
buttons.forEach((button) => {
button.addEventListener("click", () => {
const offset = button.dataset.carouselBtn === "next" ? 1 : -1;
const slidesContainer = button
.closest("[data-carousel]")
.querySelector("[data-carousel-slides");
const slides = slidesContainer.querySelectorAll("[data-carousel-slide]");
const activeSlide = slidesContainer.querySelector("[data-active]");
const activeSlideIndex = [...slides].indexOf(activeSlide);
const nextSlideIndex = activeSlideIndex + offset;
if (nextSlideIndex < 0) {
slides[slides.length + nextSlideIndex].dataset.active = true;
return delete activeSlide.dataset.active;
}
if (nextSlideIndex >= slides.length) {
slides[0].dataset.active = true;
return delete activeSlide.dataset.active;
}
slides[nextSlideIndex].dataset.active = true;
return delete activeSlide.dataset.active;
});
});
.carouselContainer {
width: 1000px;
height: 500px;
position: relative;
display: flex;
justify-content: center;
border-style: dashed;
border-color: #010043;
}
.carouselContainer>ul {
padding: 0;
margin: 0;
list-style: none;
}
.slide {
display: flex;
width: 400px;
height: 500px;
justify-content: center;
align-items: center;
inset: 0;
opacity: 0;
transition-property: opacity;
transition-duration: 200ms;
transition-timing-function: ease-in-out;
transition-delay: 200ms;
border-style: dashed;
border-color: var(--magenta6);
}
.slide[data-active] {
opacity: 1;
z-index: 1;
transition-delay: 0ms;
}
.slideContent {
display: flex;
justify-content: space-between;
align-items: center;
flex-direction: column;
width: 300px;
height: 425px;
border-style: dashed;
border-color: #010043;
}
.slideContent .slideImg {
margin: 0;
width: 200px;
height: 200px;
border-radius: 100px;
z-index: 10px;
}
.slideContent .slideTxt {
border: magenta;
border-style: dashed;
height: 500px;
}
.carousel-button {
position: absolute;
background: none;
border: none;
outline: none;
font-size: 4rem;
top: 50%;
transform: translateY(-50%);
z-index: 2;
color: rgba(255, 255, 255, 0.5);
cursor: pointer;
padding: 0 0.5rem;
border-radius: 0.25rem;
background-color: rgba(0, 0, 0, 0.1);
transition: 0.5s;
}
.carousel-button:hover,
.carousel-button:focus {
background-color: rgba(0, 0, 0, 0.3);
color: #fff;
}
.carousel-button[data-carousel-btn="prev"] {
left: 1rem;
}
.carousel-button[data-carousel-btn="next"] {
right: 1rem;
}
<section class="row4 animateOnScroll" style="margin: 0 100px 100px 100px;">
<h2>don't just take it from us!</h2>
<div class="carouselContainer" data-carousel>
<button class="carousel-button" data-carousel-btn="prev">
❮
</button>
<button class="carousel-button" data-carousel-btn="next">
❯
</button>
<div class="carouselSlides">
<ul data-carousel-slides>
<li class="slide" data-carousel-slide data-active>
<div class="slideContent">
<div>
<img class="slideImg" src="./assets/imgPlaceholder.jpg">
</div>
<div class="slideTxt">
<div class="slideDesc">
<p style="color:black;">hello</p>
</div>
</div>
</div>
</li>
<li class="slide" data-carousel-slide>
<div class="slideContent">
<div>
<img class="slideImg" src="./assets/imgPlaceholder.jpg">
</div>
<div class="slideTxt">
<div class="slideDesc">
<p style="color:black;">hello</p>
</div>
</div>
</div>
</li>
<li class="slide" data-carousel-slide>
<div class="slideContent">
<div>
<img class="slideImg" src="./assets/imgPlaceholder.jpg">
</div>
<div class="slideTxt">
<div class="slideDesc">
<p style="color:black;">hello</p>
</div>
</div>
</div>
</ul>
</div>
</div>
</section>
part of your problem is your ul element is unstyled, its child li elements are going to stack as they normally do on top of each other. giving the ul element display: flex; will put your li's side by side.
If I were you, I would review each nested element of my tree and figure out its purpose, then remove it if not necessary. for example, div.carouselSlides does not seem like its serving any purpose that the ul could not do itself, at least in this small example.
Also, looking at an established project for implementation ideas (or just using it) might be a good idea . https://swiperjs.com/ is very established with powerful config options
Basically there should be 2 containers:
The element that is the parent of the <button>s and the "frame" that holds each slide. In the example it is article.box.
The element that is the parent of each div.slide in the example is section.frame.
Each container should be position: relative and all children of said containers should be position: absolute. Doing so will:
provide precision positioning of the <button>s and section.frame within the perimeters of article.box
allow all div.slide to hide underneath the visible layers (z-index:0+) with z-index: -1 and be visible with .active class at z-index: 1.
The JavaScript is optional, it's just written better but function should be basically the same.
View in full page mode, the image placeholder service does not have dynamic images.
const data = [
{img:"https://placem.at/people?random=1", cap:"People 1"},
{img:"https://placem.at/places?random=1", cap:"Places 2"},
{img:"https://placem.at/things?random=1", cap:"Things 3"}
];
const slides = genSlides(data);
const box = document.querySelector('.box')
const buttons = box.querySelectorAll("button");
buttons.forEach((button) => {
button.addEventListener("click", function(event) {
const offset = button.classList.contains("next") ? 1 : -1;
const active = box.querySelector(".active");
const actIdx = slides.indexOf(active);
const nextIdx = actIdx + offset;
active.classList.remove("active");
if (nextIdx < 0) {
return slides[slides.length + nextIdx].classList.add("active");
}
if (nextIdx >= slides.length) {
return slides[0].classList.add("active");
}
return slides[nextIdx].classList.add("active");
});
});
function genSlides(array) {
const frame = document.querySelector(".frame");
array.forEach(slide => {
frame.insertAdjacentHTML("beforeend", `
<div class="slide">
<figure>
<img src="${slide.img}" width="480">
<figcaption class="cap">${slide.cap}</figcaption>
</figure>
</div>`);
});
const slides = Array.from(frame.querySelectorAll(".slide"));
slides[0].classList.add("active");
return slides;
}
.box {
display: flex;
justify-content: center;
align-items: center;
position: relative;
width: 96vw;
min-height: 96vh;
border: 3px dashed #000;
}
.frame {
display: flex;
flex-flow: column nowrap;
justify-content: center;
align-items: center;
/* The element that is the parent of all .slide should be relative so the
slides, which are absolute positioned, can sit within .frame's perimeter */
position: relative;
}
.slide {
display: flex;
width: 100%;
height: 100%;
justify-content: center;
align-items: center;
/* All slides should be out of normal flow */
position: absolute;
/* All slides should be in the layer "under" the visible layer (z-index: 0+) */
z-index: -1;
opacity: 0;
animation: opacity 0.7s ease-in;
}
.active {
opacity: 1;
z-index: 1;
}
figure {
display: flex;
flex-flow: column nowrap;
justify-content: center;
align-items: center;
max-height: 100%;
margin: 0;
padding: 0;
border-style: 1px dashed #000;
}
img {
object-fit: contain;
}
.cap {
min-width: 100%;
text-align: center;
white-space: pre;
}
button {
display: inline-flex;
justify-content: center;
align-items: center;
position: absolute;
top: 50%;
z-index: 2;
padding: 0 0.5rem;
border: none;
border-radius: 0.25rem;
outline: none;
font-size: 4rem;
color: rgba(255, 255, 255, 0.5);
background: none;
background-color: rgba(0, 0, 0, 0.1);
transform: translateY(-50%);
transition: 0.5s;
cursor: pointer;
}
button:hover,
button:focus {
color: #fff;
background-color: rgba(0, 0, 0, 0.3);
}
button:active {
color: rgba(0, 0, 0, 0.5);
background: none;
}
.prev {
left: 1rem;
}
.next {
right: 1rem;
}
<main>
<h2>Content Title</h2>
<article class="box">
<button class="prev">❮</button>
<button class="next">❯</button>
<section class="frame"></section>
</article>
</main>

The changing volume icon pushes the volume slider. css problem

is there an easy fix to separate the volume icon from the volume slider? I have the volume icon change depending on the slider value but it feels janky because the size of the icon changes and pushes everything. I think you can c/p the code on replit and see the problem with the volume slider.
I tried aligning it to the right or changing the position using transform but it doesn't seem to fix the problem.
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<link href="style.css" rel="stylesheet" type="text/css" />
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
/>
</head>
<body>
<div class="video-player">
<video id="myVideo" poster="Poke_Ball.png">
<source src="https://www.youtube.com/watch?v=Y3xgmGSnzlU" class="video">
</video>
<div class="player-controls">
<div class="video-progress">
<div class="video-progress-filled"></div>
</div>
<button id="btnPlay"><i class="fa fa-play-circle-o"></i></button>
<button id="btnPause" class="hidden"><i class="fa fa-pause-circle-o"></i></button>
<button id="volumeNone" class="hidden"><i class="fa fa-volume-off"></i></button>
<button id="volumeLow" class="hidden"><i class="fa fa-volume-down"></i></button>
<button id="volumeHigh"><i class="fa fa-volume-up"></i></button>
<input type="range" class="volume" min="0" max="1" step="0.01" value=".5"/>
</div>
</div>
<script src="script.js"></script>
</body>
</html>
.hidden {
display: none;
}
.video-player {
max-width: 100%;
position: relative;
overflow: hidden;
}
.player-controls {
display: flex;
position: absolute;
bottom: 0;
width: 100%;
transform: translateY(100%) translateY(-5px);
transition: 0.3s;
flex-wrap: wrap;
background: rgba(0, 0, 0, 0.6);
}
.video-player:hover .player-controls {
transform: translateY(0);
}
.video-progress {
position: relative;
display: flex;
width: 100%;
height: 5px;
transition: 0.3s;
background: rgba(0, 0, 0, 0.6);
cursor: pointer;
}
.video-progress-filled {
width: 0;
background: orangered;
}
.video-player:hover .video-progress {
height: 13px;
}
input[type="range"] {
-webkit-appearance: none;
background: transparent;
margin: 0;
width: 7%;
padding: 0 10px;
}
input[type="range"]:focus {
outline: none;
}
input[type="range"]::-webkit-slider-runnable-track {
width: 5%;
height: 10px;
cursor: pointer;
background: white;
}
input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
height: 10px;
width: 13px;
background: orangered;
cursor: pointer;
}
#timeOut{
font-family: monospace;
font-size: 120%;
padding: 18px;
color: white;
border: none;
background: none;
}
#btnPlay,#btnPause,#volumeNone,#volumeLow,#volumeHigh {
font-size: 200%;
padding: 10px;
color: white;
border: none;
background: none;
}
#btnPlay:hover,#btnPause:hover,#volumeNone:hover,#volumeLow:hover,#volumeHigh:hover {
transition: all 0.1s ease;
color: orangered;
}
const volume = document.querySelector('.volume');
const volumeNone = document.getElementById("volumeNone");
const volumeLow = document.getElementById("volumeLow");
const volumeHigh = document.getElementById("volumeHigh");
const myVideo = document.getElementById("myVideo");
const btnPlay = document.getElementById("btnPlay");
const btnPause = document.getElementById("btnPause");
btnPlay.addEventListener("click", vidPlay);
btnPause.addEventListener("click", vidPause);
volume.addEventListener('mousemove', (e)=> {
myVideo.volume = e.target.value;
if(myVideo.volume === 0){
volumeNone.classList.remove("hidden");
volumeLow.classList.add("hidden");
volumeHigh.classList.add("hidden");
}
else if(myVideo.volume < .5 && myVideo.volume > .1){
volumeNone.classList.add("hidden");
volumeLow.classList.remove("hidden");
volumeHigh.classList.add("hidden");
}
else if(myVideo.volume > .5) {
volumeNone.classList.add("hidden");
volumeLow.classList.add("hidden");
volumeHigh.classList.remove("hidden");
}
})
function vidPlay() {
btnPlay.classList.add("hidden");
btnPause.classList.remove("hidden");
myVideo.play();
}
function vidPause() {
btnPlay.classList.remove("hidden");
btnPause.classList.add("hidden");
myVideo.pause();
}
is there an easy fix to separate the volume icon from the volume slider?
- Simply removing the code
You can remove the code that makes the volume icon synchronized with the volume slider in the first place.
const volume = document.querySelector('.volume');
const volumeNone = document.getElementById("volumeNone");
const volumeLow = document.getElementById("volumeLow");
const volumeHigh = document.getElementById("volumeHigh");
const myVideo = document.getElementById("myVideo");
const btnPlay = document.getElementById("btnPlay");
const btnPause = document.getElementById("btnPause");
btnPlay.addEventListener("click", vidPlay);
btnPause.addEventListener("click", vidPause);
/* volume.addEventListener('mousemove', (e)=> {
myVideo.volume = e.target.value;
if(myVideo.volume === 0){
volumeNone.classList.remove("hidden");
volumeLow.classList.add("hidden");
volumeHigh.classList.add("hidden");
}
else if(myVideo.volume < .5 && myVideo.volume > .1){
volumeNone.classList.add("hidden");
volumeLow.classList.remove("hidden");
volumeHigh.classList.add("hidden");
}
else if(myVideo.volume > .5) {
volumeNone.classList.add("hidden");
volumeLow.classList.add("hidden");
volumeHigh.classList.remove("hidden");
}
})
*/
function vidPlay() {
btnPlay.classList.add("hidden");
btnPause.classList.remove("hidden");
myVideo.play();
}
function vidPause() {
btnPlay.classList.remove("hidden");
btnPause.classList.add("hidden");
myVideo.pause();
}
.hidden {
display: none;
}
.video-player {
max-width: 100%;
position: relative;
overflow: hidden;
}
.player-controls {
display: flex;
position: absolute;
bottom: 0;
width: 100%;
transform: translateY(100%) translateY(-5px);
transition: 0.3s;
flex-wrap: wrap;
background: rgba(0, 0, 0, 0.6);
}
.video-player:hover .player-controls {
transform: translateY(0);
}
.video-progress {
position: relative;
display: flex;
width: 100%;
height: 5px;
transition: 0.3s;
background: rgba(0, 0, 0, 0.6);
cursor: pointer;
}
.video-progress-filled {
width: 0;
background: orangered;
}
.video-player:hover .video-progress {
height: 13px;
}
input[type="range"] {
-webkit-appearance: none;
background: transparent;
margin: 0;
width: 7%;
padding: 0 10px;
}
input[type="range"]:focus {
outline: none;
}
input[type="range"]::-webkit-slider-runnable-track {
width: 5%;
height: 10px;
cursor: pointer;
background: white;
}
input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
height: 10px;
width: 13px;
background: orangered;
cursor: pointer;
}
#timeOut{
font-family: monospace;
font-size: 120%;
padding: 18px;
color: white;
border: none;
background: none;
}
#btnPlay,#btnPause,#volumeNone,#volumeLow,#volumeHigh {
font-size: 200%;
padding: 10px;
color: white;
border: none;
background: none;
}
#btnPlay:hover,#btnPause:hover,#volumeNone:hover,#volumeLow:hover,#volumeHigh:hover {
transition: all 0.1s ease;
color: orangered;
}
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<link href="style.css" rel="stylesheet" type="text/css" />
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
/>
</head>
<body>
<div class="video-player">
<video id="myVideo" poster="Poke_Ball.png">
<source src="https://www.youtube.com/watch?v=Y3xgmGSnzlU" class="video">
</video>
<div class="player-controls">
<div class="video-progress">
<div class="video-progress-filled"></div>
</div>
<button id="btnPlay"><i class="fa fa-play-circle-o"></i></button>
<button id="btnPause" class="hidden"><i class="fa fa-pause-circle-o"></i></button>
<button id="volumeNone" class="hidden"><i class="fa fa-volume-off"></i></button>
<button id="volumeLow" class="hidden"><i class="fa fa-volume-down"></i></button>
<button id="volumeHigh"><i class="fa fa-volume-up"></i></button>
<input type="range" class="volume" min="0" max="1" step="0.01" value=".5"/>
</div>
</div>
<script src="script.js"></script>
</body>
</html>
- Quick and easy fix instead of giving up on the idea
If the only reason you don't want to use this code is because it "feels janky", I fixed it by adding `min-width: 60px;` to `#btnPlay,#btnPause,#volumeNone,#volumeLow,#volumeHigh`. The problem was that the `volumeHigh`'s width was larger than `volumeLow` and `volumeNone`'s. fixing all the icon's width at a minimum of 60px solved the problem. `width: 60px` will also work.
const volume = document.querySelector('.volume');
const volumeNone = document.getElementById("volumeNone");
const volumeLow = document.getElementById("volumeLow");
const volumeHigh = document.getElementById("volumeHigh");
const myVideo = document.getElementById("myVideo");
const btnPlay = document.getElementById("btnPlay");
const btnPause = document.getElementById("btnPause");
btnPlay.addEventListener("click", vidPlay);
btnPause.addEventListener("click", vidPause);
volume.addEventListener('mousemove', (e)=> {
myVideo.volume = e.target.value;
if(myVideo.volume === 0){
volumeNone.classList.remove("hidden");
volumeLow.classList.add("hidden");
volumeHigh.classList.add("hidden");
}
else if(myVideo.volume < .5 && myVideo.volume > .1){
volumeNone.classList.add("hidden");
volumeLow.classList.remove("hidden");
volumeHigh.classList.add("hidden");
}
else if(myVideo.volume > .5) {
volumeNone.classList.add("hidden");
volumeLow.classList.add("hidden");
volumeHigh.classList.remove("hidden");
}
})
function vidPlay() {
btnPlay.classList.add("hidden");
btnPause.classList.remove("hidden");
myVideo.play();
}
function vidPause() {
btnPlay.classList.remove("hidden");
btnPause.classList.add("hidden");
myVideo.pause();
}
.hidden {
display: none;
}
.video-player {
max-width: 100%;
position: relative;
overflow: hidden;
}
.player-controls {
display: flex;
position: absolute;
bottom: 0;
width: 100%;
transform: translateY(100%) translateY(-5px);
transition: 0.3s;
flex-wrap: wrap;
background: rgba(0, 0, 0, 0.6);
}
.video-player:hover .player-controls {
transform: translateY(0);
}
.video-progress {
position: relative;
display: flex;
width: 100%;
height: 5px;
transition: 0.3s;
background: rgba(0, 0, 0, 0.6);
cursor: pointer;
}
.video-progress-filled {
width: 0;
background: orangered;
}
.video-player:hover .video-progress {
height: 13px;
}
input[type="range"] {
-webkit-appearance: none;
background: transparent;
margin: 0;
width: 7%;
padding: 0 10px;
}
input[type="range"]:focus {
outline: none;
}
input[type="range"]::-webkit-slider-runnable-track {
width: 5%;
height: 10px;
cursor: pointer;
background: white;
}
input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
height: 10px;
width: 13px;
background: orangered;
cursor: pointer;
}
#timeOut{
font-family: monospace;
font-size: 120%;
padding: 18px;
color: white;
border: none;
background: none;
}
#btnPlay,#btnPause,#volumeNone,#volumeLow,#volumeHigh {
font-size: 200%;
padding: 10px;
color: white;
border: none;
background: none;
min-width: 60px;
}
#btnPlay:hover,#btnPause:hover,#volumeNone:hover,#volumeLow:hover,#volumeHigh:hover {
transition: all 0.1s ease;
color: orangered;
}
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<link href="style.css" rel="stylesheet" type="text/css" />
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
/>
</head>
<body>
<div class="video-player">
<video id="myVideo" poster="Poke_Ball.png">
<source src="https://www.youtube.com/watch?v=Y3xgmGSnzlU" class="video">
</video>
<div class="player-controls">
<div class="video-progress">
<div class="video-progress-filled"></div>
</div>
<button id="btnPlay"><i class="fa fa-play-circle-o"></i></button>
<button id="btnPause" class="hidden"><i class="fa fa-pause-circle-o"></i></button>
<button id="volumeNone" class="hidden"><i class="fa fa-volume-off"></i></button>
<button id="volumeLow" class="hidden"><i class="fa fa-volume-down"></i></button>
<button id="volumeHigh"><i class="fa fa-volume-up"></i></button>
<input type="range" class="volume" min="0" max="1" step="0.01" value=".5"/>
</div>
</div>
<script src="script.js"></script>
</body>
</html>
I'm not sure if this is different in a video player for whatever reason but when facing issues like that in the past I usually will wrap the icon in some kind of container that is big enough to accommodate the biggest icon. It needs to have either static dimensions or dimensions that are informed by something other than its contents.
Then you can either give it position relative and center the icons absolutely, or (and this is what I recommend) you can just use flexbox to center the icon.
Here is a Svelte Repl with an example. If you don't know svelte don't worry just know I'm switching between a 24x24 icon and a 34x34 icon and am using the button as the container. The styles are in a style tag at the bottom.
https://svelte.dev/repl/34a316c3169248ce84b18972ab4953f5?version=3.47.0

multiple sliders in one page website with javascript

I have to multiple sliders in my website. this code not work in my page for 3 sliders in one page.
but worked in one slider in one page. please help me do I it?
I need that this sliders worked in one page in my website. This sliders have to work into the accordion hover in one page.
The problem is that when I put all the slides, they all come together in one accordion.
In general, the main problem is that three sliders on one page do not work with this code
const slider = function () {
// const this_slider = this;
const slides = document.querySelectorAll('.slide');
const btnLeft = document.querySelector('.slider__btn--left');
const btnRight = document.querySelector('.slider__btn--right');
const dotContainer = document.querySelector('.dots');
let curSlide = 0;
const maxSlide = slides.length;
// Functions
const createDots = function () {
slides.forEach(function (_, i) {
dotContainer.insertAdjacentHTML(
'beforeend',
`<button class="dots__dot" data-slide="${i}"></button>`
);
});
};
const activateDot = function (slide) {
document
.querySelectorAll('.dots__dot')
.forEach(dot => dot.classList.remove('dots__dot--active'));
document
.querySelector(`.dots__dot[data-slide="${slide}"]`)
.classList.add('dots__dot--active');
};
const goToSlide = function (slide) {
slides.forEach(
(s, i) => (s.style.transform = `translateX(${100 * (i - slide)}%)`)
);
};
// Next slide
const nextSlide = function () {
if (curSlide === maxSlide - 1) {
curSlide = 0;
} else {
curSlide++;
}
goToSlide(curSlide);
activateDot(curSlide);
};
const prevSlide = function () {
if (curSlide === 0) {
curSlide = maxSlide - 1;
} else {
curSlide--;
}
goToSlide(curSlide);
activateDot(curSlide);
};
const init = function () {
goToSlide(0);
createDots();
activateDot(0);
};
init();
// Event handlers
btnRight.addEventListener('click', nextSlide);
btnLeft.addEventListener('click', prevSlide);
document.addEventListener('keydown', function (e) {
if (e.key === 'ArrowLeft') prevSlide();
e.key === 'ArrowRight' && nextSlide();
});
dotContainer.addEventListener('click', function (e) {
if (e.target.classList.contains('dots__dot')) {
const { slide } = e.target.dataset;
goToSlide(slide);
activateDot(slide);
}
});
};
slider();
/* SLIDER */
.slider {
max-width: 100rem;
height: 50rem;
margin: 0 auto;
position: relative;
/* IN THE END */
overflow: hidden;
}
.slide {
position: absolute;
top: 0;
width: 100%;
height: 50rem;
display: flex;
align-items: center;
justify-content: center;
/* THIS creates the animation! */
transition: transform 1s;
}
.slide > img {
/* Only for images that have different size than slide */
width: 100%;
height: 100%;
object-fit: cover;
}
.slider__btn {
position: absolute;
top: 50%;
z-index: 10;
border: none;
background-color: inherit;
/* background: rgba(255, 255, 255, 0.7); */
font-family: inherit;
color: white;
border-radius: 50%;
height: 5.5rem;
width: 5.5rem;
font-size: 3.25rem;
cursor: pointer;
}
.slider__btn--left {
left: 6%;
transform: translate(-50%, -50%);
}
.slider__btn--right {
right: 6%;
transform: translate(50%, -50%);
}
.dots {
position: absolute;
bottom: 5%;
left: 50%;
transform: translateX(-50%);
display: flex;
}
.dots__dot {
border: none;
background-color: #b9b9b9;
opacity: 0.7;
height: 1rem;
width: 1rem;
border-radius: 50%;
margin-right: 1.75rem;
cursor: pointer;
transition: all 0.5s;
/* Only necessary when overlying images */
/* box-shadow: 0 0.6rem 1.5rem rgba(0, 0, 0, 0.7); */
}
.dots__dot:last-child {
margin: 0;
}
.dots__dot--active {
/* background-color: #fff; */
background-color: blue;
opacity: 1;
}
.slideshow-container {
max-width: 1000px;
position: relative;
margin: auto;
}
/* Next & previous buttons */
.prev,
.next {
cursor: pointer;
position: absolute;
top: 50%;
width: auto;
padding: 16px;
margin-top: -22px;
color: white;
font-weight: bold;
font-size: 18px;
transition: 0.6s ease;
border-radius: 0 3px 3px 0;
user-select: none;
}
/* Position the "next button" to the right */
.next {
right: 0;
border-radius: 3px 0 0 3px;
}
/* On hover, add a grey background color */
.prev:hover,
.next:hover {
background-color: #f1f1f1;
color: black;
}
<div class="slider">
<div class="slide">
<img src="img/img-1.jpg" alt="">
</div>
<div class="slide">
<img src="img/img-2.jpg" alt="">
</div>
<div class="slide">
<img src="img/img-3.jpg" alt="">
</div>
<div class="slide">
<img src="img/img-4.jpg" alt="">
</div>
<button class="slider__btn slider__btn--left">❮</button>
<button class="slider__btn slider__btn--right">❯</button>
<div class="dots"></div>
</div>
I have modified your html, css and script for demo.
html - added two more sliders and separated them.
css - added button colors for visibility
javascript - you can see it.
// We have to declare the function for all the sliders
// get all slider from document.
const slideContainer = document.querySelectorAll('.slider');
// lets put your function to every one of them
for(let i = 0; i < slideContainer.length; i++){
const slider = function () {
// const this_slider = this;
const slides = slideContainer[i].querySelectorAll('.slide'); // Your code was : const slides = document.querySelectorAll('.slide'); don't search the entire document, only search the slider
const btnLeft = slideContainer[i].querySelector('.slider__btn--left');
const btnRight = slideContainer[i].querySelector('.slider__btn--right');
const dotContainer = slideContainer[i].querySelector('.dots');
let curSlide = 0;
const maxSlide = slides.length;
// Functions
const createDots = function () {
slides.forEach(function (_, i) {
dotContainer.insertAdjacentHTML(
'beforeend',
`<button class="dots__dot" data-slide="${i}"></button>`
);
});
};
const activateDot = function (slide) {
slideContainer[i]
.querySelectorAll('.dots__dot')
.forEach(dot => dot.classList.remove('dots__dot--active'));
slideContainer[i]
.querySelector(`.dots__dot[data-slide="${slide}"]`)
.classList.add('dots__dot--active');
};
const goToSlide = function (slide) {
slides.forEach(
(s, i) => (s.style.transform = `translateX(${100 * (i - slide)}%)`)
);
};
// Next slide
const nextSlide = function () {
if (curSlide === maxSlide - 1) {
curSlide = 0;
} else {
curSlide++;
}
goToSlide(curSlide);
activateDot(curSlide);
};
const prevSlide = function () {
if (curSlide === 0) {
curSlide = maxSlide - 1;
} else {
curSlide--;
}
goToSlide(curSlide);
activateDot(curSlide);
};
const init = function () {
goToSlide(0);
createDots();
activateDot(0);
};
init();
// Event handlers
btnRight.addEventListener('click', nextSlide);
btnLeft.addEventListener('click', prevSlide);
document.addEventListener('keydown', function (e) {
if (e.key === 'ArrowLeft') prevSlide();
e.key === 'ArrowRight' && nextSlide();
});
dotContainer.addEventListener('click', function (e) {
if (e.target.classList.contains('dots__dot')) {
const { slide } = e.target.dataset;
goToSlide(slide);
activateDot(slide);
}
});
};
slider();
}
/* SLIDER */
.slider {
max-width: 100rem;
height: 50rem;
margin: 0 auto;
position: relative;
/* IN THE END */
overflow: hidden;
}
.slide {
position: absolute;
top: 0;
width: 100%;
height: 50rem;
display: flex;
align-items: center;
justify-content: center;
/* THIS creates the animation! */
transition: transform 1s;
}
.slide > img {
/* Only for images that have different size than slide */
width: 100%;
height: 100%;
object-fit: cover;
}
.slider__btn {
position: absolute;
top: 50%;
z-index: 10;
border: none;
background-color: black; // your was "inherit" . changed this for my visibility.
/* background: rgba(255, 255, 255, 0.7); */
font-family: inherit;
color: white;
border-radius: 50%;
height: 5.5rem;
width: 5.5rem;
font-size: 3.25rem;
cursor: pointer;
}
.slider__btn--left {
left: 6%;
transform: translate(-50%, -50%);
}
.slider__btn--right {
right: 6%;
transform: translate(50%, -50%);
}
.dots {
position: absolute;
bottom: 5%;
left: 50%;
transform: translateX(-50%);
display: flex;
}
.dots__dot {
border: none;
background-color: #b9b9b9;
opacity: 0.7;
height: 1rem;
width: 1rem;
border-radius: 50%;
margin-right: 1.75rem;
cursor: pointer;
transition: all 0.5s;
/* Only necessary when overlying images */
/* box-shadow: 0 0.6rem 1.5rem rgba(0, 0, 0, 0.7); */
}
.dots__dot:last-child {
margin: 0;
}
.dots__dot--active {
/* background-color: #fff; */
background-color: blue;
opacity: 1;
}
.slideshow-container {
max-width: 1000px;
position: relative;
margin: auto;
}
/* Next & previous buttons */
.prev,
.next {
cursor: pointer;
position: absolute;
top: 50%;
width: auto;
padding: 16px;
margin-top: -22px;
color: white;
font-weight: bold;
font-size: 18px;
transition: 0.6s ease;
border-radius: 0 3px 3px 0;
user-select: none;
}
/* Position the "next button" to the right */
.next {
right: 0;
border-radius: 3px 0 0 3px;
}
/* On hover, add a grey background color */
.prev:hover,
.next:hover {
background-color: #f1f1f1;
color: black;
}
<div class="slider">
<div class="slide">
<img src="img/img-1.jpg" alt="">
</div>
<div class="slide">
<img src="img/img-2.jpg" alt="">
</div>
<div class="slide">
<img src="img/img-3.jpg" alt="">
</div>
<div class="slide">
<img src="img/img-4.jpg" alt="">
</div>
<button class="slider__btn slider__btn--left">❮</button>
<button class="slider__btn slider__btn--right">❯</button>
<div class="dots"></div>
</div>
<hr> <!-- This to separate the slider (optional)-->
<div class="slider">
<div class="slide">
<img src="img/img-1.jpg" alt="">
</div>
<div class="slide">
<img src="img/img-2.jpg" alt="">
</div>
<div class="slide">
<img src="img/img-3.jpg" alt="">
</div>
<div class="slide">
<img src="img/img-4.jpg" alt="">
</div>
<button class="slider__btn slider__btn--left">❮</button>
<button class="slider__btn slider__btn--right">❯</button>
<div class="dots"></div>
</div>
<hr> <!-- This to separate the slider (optional)-->
<div class="slider">
<div class="slide">
<img src="img/img-1.jpg" alt="">
</div>
<div class="slide">
<img src="img/img-2.jpg" alt="">
</div>
<div class="slide">
<img src="img/img-3.jpg" alt="">
</div>
<div class="slide">
<img src="img/img-4.jpg" alt="">
</div>
<button class="slider__btn slider__btn--left">❮</button>
<button class="slider__btn slider__btn--right">❯</button>
<div class="dots"></div>
</div>

Javascript: Carousel active dots and left-right buttons

I am beginner level javascript developer. I have decide to make carousel by using pure Javascript. I successfully manage to slide the carousel. I have decided to make active dots(also clickable), i want the dots background colour change when slide happen and left-right button. I have created the dots but I don't know how to implement the dots in my slide function as well left and right button. Here is my code:
Also please explain me the logic. Thank you
const images = document.getElementById('imgs');
const allImages = document.querySelectorAll('#imgs img');
const leftBtn = document.getElementById('left');
const rightBtn = document.getElementById('right');
let index = 0;
function run() {
const dot = [...document.getElementsByClassName('star')];
index++;
if (index > allImages.length - 1) {
index = 0
dot.forEach(i => i.classList.add('active'))
}
imgs.style.transform = `translateX(${-index * 500}px)`
}
const dot = allImages.forEach(i => {
const elem = document.createElement('div');
elem.classList.add('star');
document.body.appendChild(elem)
})
let x = setInterval(run, 2000);
images.onmouseover = () => {
clearInterval(x)
}
images.onmouseout = () => {
x = setInterval(run, 2000);
}
*{
box-sizing: border-box;
}
body {
margin: 0;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
.carousel {
overflow: hidden;
width: 500px;
height: 500px;
box-shadow: 2px 2px 5px rgba(0, 0, 0, .3);
border-radius: 5px;
}
.image-container {
display: flex;
transition: transform 300ms linear;
transform: translateX(0);
}
img {
width:500px;
height: 500px;
object-fit: cover;
}
.star{
cursor: pointer;
height: 15px;
width: 15px;
margin: 0 10px;
border-radius: 50%;
display: inline-block;
transition: background-color 0.6s ease;
background-color: #eeeeee;
}
.star.active{
background-color: red;
}
button{
cursor: pointer;
position: relative;
font-size: 18px;
transition: 0.6s ease;
user-select: none;
height: 50px;
width: 40px;
display: flex;
justify-content: center;
align-items: center;
align-content: center;
top: calc(50% - 25px);
}
button:hover {
background-color: rgba(0,0,0,0.8);
};
button.left {
border-radius: 3px 0 0 3px;
right: 0;
}
button.left {
border-radius: 3px 0 0 3px;
left: 0;
}
<button id="left">❮</button>
<button id="right">❯</button>
<div class="carousel">
<div class="image-container" id="imgs" >
<img src="https://images.unsplash.com/photo-1599736375341-51b0a848f3c7?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=800&q=60" alt="">
<img src="https://images.unsplash.com/photo-1516026672322-bc52d61a55d5?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=800&q=60" alt="">
<img src="https://images.unsplash.com/photo-1573081586928-127ecc7948b0?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=800&q=60" alt="">
<img src="https://images.unsplash.com/flagged/photo-1572850005109-f4ac7529bf9f?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=800&q=60" alt="">
</div>
</div>
You were close to the result. In your run function, you just have to change the class of the current active dot and set the new one to active. I renamed your dot variable to dots for the sake of comprehension.
function run() {
const dots = [...document.getElementsByClassName('star')];
index++;
if (index > allImages.length - 1) {
index = 0
}
dots.forEach((dot, i) => {
if (dot.classList.contains('active')) dot.classList.remove('active');
if (i === index) dot.classList.add('active'));
}
imgs.style.transform = `translateX(${-index * 500}px)`
}

Categories

Resources