Nested scroll inside vertical swiper slide when mousewheel: true - javascript

I have a vertical slider and I'm using swiper to navigate through the slides.
Every swiper-slide container height is 100vh.
I have a slide which content is greater than the view height and when scrolling with the mousewheel, I want to first scroll it's content and when the end or top is reached, according to the scroll direction, move to the next or previous slide.
I went through swiper documentation, SO and other pages but didn't find a solution.
Here is the jsfiddle:
https://jsfiddle.net/gentian28/6wdsep1v/13/
HTML
<div class="swiper-container">
<main class="main swiper-wrapper">
<!-- landing -->
<section id="home" class="swiper-slide">
<div id="particles-js"></div>
<div id="typeIt" class="d-flex align-center"></div>
</section>
<!-- about -->
<section id="about" class="swiper-slide">
<span class="animation">About</span>
</section>
<!-- portfolio -->
<section id="portfolio" class="swiper-slide d-flex flex-wrap col-3">
<div class="card">
card 1
</div>
<div class="card">
card 2
</div>
<div class="card">
card 3
</div>
<div class="card">
card 4
</div>
<div class="card">
card 1
</div>
<div class="card">
card 1
</div>
<div class="card">
card 1
</div>
<div class="card">
card 1
</div>
<div class="card">
card 1
</div>
<div class="card">
card 1
</div>
<div class="card">
card 1
</div>
</section>
<!-- technologies -->
<section id="skills" class="swiper-slide">
Skills
</section>
<!-- contact -->
<section id="contact" class="swiper-slide">
Contact
</section>
</main>
</div>
CSS
body {
margin: 0;
padding: 0;
}
.d-flex {
display: flex;
}
.align-center {
align-items: center;
}
.justify-center {
justify-content: center;
}
.justify-between {
justify-content: space-between;
}
.flex-column {
flex-flow: column;
}
.column-reverse {
flex-flow: column-reverse;
}
.flex-wrap {
flex-wrap: wrap;
}
.col-2 > * {
width: calc(100% / 2 - 7.5px);
margin-right: 15px;
margin-bottom: 15px;
}
.col-2 > *:nth-child(2n) {
margin-right: 0;
}
.col-3 > * {
width: calc(100% / 3 - 10px);
margin-right: 15px;
}
.col-3 > *:nth-child(3n) {
margin-right: 0;
}
.col-4 > * {
width: calc(100% / 4 - 10.5px);
margin-right: 14px;
}
.col-4 > *:nth-child(4n) {
margin-right: 0;
}
.card {
height: 300px;
}
.swiper-container {
width: 100% - 120px;
height: 100vh;
margin-left: auto;
margin-right: auto;
}
.swiper-slide {
text-align: center;
font-size: 18px;
background: #fff;
/* Center slide text vertically */
display: -webkit-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-webkit-box-pack: center;
-ms-flex-pack: center;
-webkit-justify-content: center;
justify-content: center;
-webkit-box-align: center;
-ms-flex-align: center;
-webkit-align-items: center;
align-items: center;
overflow-y: auto;
}
.swiper-pagination {
display: flex;
flex-flow: column;
}
.swiper-pagination-bullet-active {
opacity: 0;
}
.swiper-pagination-bullet {
width: 120px;
height: 96px;
border-radius: 0;
opacity: 0;
}
JS
const swiperConf = {
direction: 'vertical',
slidesPerView: 1,
spaceBetween: -1,
mousewheel: true,
keyboard: true,
pagination: {
el: '.swiper-pagination',
clickable: true,
}
}
var swiper = new Swiper('.swiper-container', swiperConf);

ahh guys! thank you a lot for the input, i had the same issue. but your solutions didnt work for me on mobile devices.
so i tried sth own with your input and hacked a little bit.
so here is mine:
(my first post on stack overflow yee)
const handleScrollInside = (swiper) => {
swiper.on("slideChangeTransitionEnd", () => {
const activeSlide = document.querySelector('.swiper-slide-active');
const hasVerticalScrollbar = activeSlide.scrollHeight > activeSlide.clientHeight;
if (hasVerticalScrollbar) {
const scrollDifferenceTop = activeSlide.scrollHeight - activeSlide.swiperSlideSize;
if (activeSlide.scrollTop === 0) activeSlide.scrollTop += 1;
if (activeSlide.scrollTop === scrollDifferenceTop) activeSlide.scrollTop -= 2;
swiper.mousewheel.disable();
swiper.allowTouchMove = false;
activeSlide.addEventListener("scroll", () => {
if (activeSlide.scrollTop <= 0 || scrollDifferenceTop - activeSlide.scrollTop <= 1 ) {
swiper.mousewheel.enable();
swiper.allowTouchMove = true;
}
});
}
})
}

Also ran into this issue, and the fiddle from #Daryll was very helpful, but with typescript there were some issues getting the 'swiperSlideSize' from an HTMLElement (also using reactjs there are some differences). This worked for me as the event handler for 'onSlideChangeTransitionEnd':
const allowScroll = (swiper: SwiperEvent) => {
var activeIndex = swiper.activeIndex;
var activeSlide = swiper.slides[activeIndex];
var { scrollHeight, clientHeight } = activeSlide;
const diff = scrollHeight - clientHeight;
if (diff > 0) {
const findScroll = (e) => {
const scrollUp = e.deltaY < 0;
if (scrollUp && activeSlide.scrollTop === 0) {
swiper.mousewheel.enable();
activeSlide.removeEventListener("wheel", findScroll);
} else if (!scrollUp && activeSlide.scrollTop === diff) {
swiper.mousewheel.enable();
activeSlide.scrollTop = 0;
activeSlide.removeEventListener("wheel", findScroll);
}
};
activeSlide.addEventListener("wheel", findScroll);
swiper.mousewheel.disable();
}
};
edit: the "SwiperEvent" type is an alias I'm using with import { Swiper as SwiperEvent } from "swiper"; to avoid namespace conflict with import { Swiper } from "swiper/react";
edit 2: for mobile usage, you have to consider 'touchmove' events, which don't (always?) register the 'wheel' event. By disabling 'allowTouchMove' on the swiper, you achieve the same effect on mobile as with mousewheel.disable() on desktop. Here's some code for that case:
const allowScroll = (swiper: SwiperEvent) => {
var activeIndex = swiper.activeIndex;
var activeSlide = swiper.slides[activeIndex];
var { scrollHeight, clientHeight } = activeSlide;
const diff = scrollHeight - clientHeight;
if (activeSlide.scrollTop === 0) activeSlide.scrollTop = 1;
else if (activeSlide.scrollTop === diff) activeSlide.scrollTop = diff - 1;
if (diff > 0) {
const findScroll = (e) => {
const scrollUp = e.deltaY < 0;
if (
(scrollUp || e.type === "touchmove") &&
activeSlide.scrollTop <= 0
) {
swiper.mousewheel.enable();
swiper.allowTouchMove = true;
activeSlide.removeEventListener("wheel", findScroll);
activeSlide.removeEventListener("touchmove", findScroll);
} else if (
(!scrollUp || e.type === "touchmove") &&
activeSlide.scrollTop >= diff
) {
swiper.mousewheel.enable();
swiper.allowTouchMove = true;
activeSlide.removeEventListener("wheel", findScroll);
activeSlide.removeEventListener("touchmove", findScroll);
}
};
activeSlide.addEventListener("wheel", findScroll);
activeSlide.addEventListener("touchmove", findScroll);
swiper.mousewheel.disable();
swiper.allowTouchMove = false;
}
};
Basically, by setting the scrollTop to 1px from either the top or bottom of the range, you prevent the mousewheel.enable() call from triggering immediately. In the original version, the slide would always start at the top of the scroll height when activated, while this version starts at the "top" (technically 1px down) if you're swiping down to it and the "bottom" if you're swiping up to it.

Related

Can't set element's scrollLeft properties in VueJS

I'm actually coding an infinite slider in vuejs (using Nuxt 3 RC.10) and I'm facing a problem : my scrollLeft don't want to be reset.
Let me explain. I got two rows of images, and when the left side of the second row collides with the left side of the container, I want to set the scrollLeft to 0. This works perfectly on both browser with Svelte, but I did not succeed with Vuejs. For some reason the second row is glitching.
After debuging, my condition is comes true but the problem seems to come from instruction slider.value.scrollLeft = 0
Thanks in advance for your help
Here my component Slider:
(PS: the commented overflow: hidden is for test purposes.
<script setup>
const slider = ref(null)
const scrollEnabled = ref(true)
const centeredComputed = computed(() => {
return scrollEnabled.value ? "" : "justify-content: center;"
})
function scroll() {
let rows = document.getElementsByClassName('row')
slider.value.scrollLeft += 20
if (scrollEnabled.value && rows[1].getBoundingClientRect().left <= slider.value.getBoundingClientRect().left) {
slider.value.scrollLeft = 0
}
scrollEnabled.value = rows[0].clientWidth > slider.value.clientWidth
}
onMounted(() => {
slider.value.addEventListener('scroll', scroll)
window.addEventListener('load', scroll)
window.addEventListener('resize', scroll)
})
onUnmounted(() => {
window.removeEventListener('load', scroll)
window.removeEventListener('resize', scroll)
})
</script>
<template>
<div ref="slider" class="slider" :style="centeredComputed">
<div class="row">
<img v-for="id in 32" class="logo" :src="`../assets/images/partenaires/${id}.png`" :alt="'Partenaire numéro ' + id">
</div>
<div v-if="scrollEnabled" class="row">
<img v-for="id in 32" class="logo" :src="`../assets/images/partenaires/${id}.png`" :alt="'Partenaire numéro ' + id">
</div>
</div>
</template>
<style lang='scss' scoped>
.slider {
width: 100%;
height: 100%;
white-space: nowrap;
//overflow-x: hidden;
overflow: auto;
display: flex;
flex-flow: row nowrap;
align-items: center;
justify-content: flex-start;
}
.row {
display: flex;
flex-flow: row nowrap;
align-items: center;
justify-content: flex-start;
height: 100%;
}
.logo {
display: inline-flex;
margin: 0 2rem;
height: 100%;
}
</style>

Can't horizontal scroll past 200vw

I have this code that goes from vertical to horizontal and back to vertical scrolling.
If I set the min-width to 50vw I can only see 4 sections, if I set it to 100vw (shown in example) it will only show 2 section.
There seems to be a width limit of 200vw, why can't I display anything over that?
I don't really understand why and thus I don't understand how to fix it. Here is my code:
let lastKnownScrollPosition = 0;
let deltaY = 0;
window.addEventListener("scroll", wheelHandler);
document.querySelectorAll('.sticky-container').forEach(function(container) {
const stikyContainerHeight = (container.querySelector('main').offsetWidth + window.innerHeight);
container.setAttribute('style', 'height: ' + stikyContainerHeight + 'px');
});
function isElementInViewport(el) {
const rect = el.getBoundingClientRect();
return rect.top <= 0 && rect.bottom > document.documentElement.clientHeight;
}
function wheelHandler(event) {
deltaY = window.scrollY - lastKnownScrollPosition;
lastKnownScrollPosition = window.scrollY;
const containerInViewPort = Array.from(document.querySelectorAll('.sticky-container')).filter(function(container) {
return isElementInViewport(container);
})[0];
if (!containerInViewPort) {
return;
}
var isPlaceHolderBelowTop = containerInViewPort.offsetTop < document.documentElement.scrollTop;
var isPlaceHolderBelowBottom = containerInViewPort.offsetTop + containerInViewPort.offsetHeight > document.documentElement.scrollTop;
let g_canScrollHorizontally = isPlaceHolderBelowTop && isPlaceHolderBelowBottom;
if (g_canScrollHorizontally) {
containerInViewPort.querySelector('main').scrollLeft += deltaY;
}
}
html,
body {
margin: 0;
font-family: sans-serif;
}
.vertical-section {
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
main {
overflow-x: hidden;
display: flex;
position: sticky;
top: 0;
}
h1 {
margin: 0;
padding: 0;
}
section {
min-width: 100vw; /*Works perfeclty when it's 50vw*/
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
font-size: 4ch;
}
section:nth-child(even) {
background-color: teal;
color: white;
}
<div class="vertical-section">
Content Before
</div>
<div class="sticky-container">
<main>
<section>
<h1>First</h1>
</section>
<section>
<h1>Second</h1>
</section>
<section>
<h1>Third</h1>
</section>
<section>
<h1>Fourth</h1>
</section>
<section>
<h1>Fifth</h1>
</section>
<section>
<h1>Last</h1>
</section>
</main>
</div>
<div class="vertical-section">
Content After
</div>
Can someone tell me what's going on here and how to fix it?
Basically when you scroll on the Y axis => up/down, the amount it will scroll from left to right, or on the X axis, is relevant to the height of the distance you are calculating in your forEach loop stikyContainerHeight.
For example, If your container is 500px wide using the 100vw css rule, and you have 6 elements total with 5 being past the right fold, this would basically be (500px * 6 = 3000px). When you scroll down in height, in order to get the width needed to show all 3000px, you must make your height the same in pixels. You can iterate over the elements that make up the main sections children and add those widths together or you can take the width of the screen and multiply it by the length of the parents sections children.
You are only adding enough distance in scrollable height to allow it to scroll two divs on the X axis. If you want it to scroll the entire distance, then get the width of the entire parent element and then multiply that by the amount of sections you are scrolling and apply to the stikyContainerHeight variable.
let lastKnownScrollPosition = 0;
let deltaY = 0;
// changed to a single query
const main = document.querySelector('.sticky-container');
// get the section elements so we can use its nodelist arrays length
const sec = document.querySelectorAll('.sticky-container section');
window.addEventListener("scroll", wheelHandler);
// no need for the forEach loop as there is only one element witht he class sticky-container
const stikyContainerHeight = main.getBoundingClientRect().width * sec.length;
main.setAttribute('style', 'height: ' + stikyContainerHeight + 'px');
// everything below here is the same
function isElementInViewport(el) {
const rect = el.getBoundingClientRect();
return rect.top <= 0 && rect.bottom > document.documentElement.clientHeight;
}
function wheelHandler(event) {
deltaY = window.scrollY - lastKnownScrollPosition;
lastKnownScrollPosition = window.scrollY;
const containerInViewPort = Array.from(document.querySelectorAll('.sticky-container')).filter(function(container) {
return isElementInViewport(container);
})[0];
if (!containerInViewPort) {
return;
}
var isPlaceHolderBelowTop = containerInViewPort.offsetTop < document.documentElement.scrollTop;
var isPlaceHolderBelowBottom = containerInViewPort.offsetTop + containerInViewPort.offsetHeight > document.documentElement.scrollTop;
let g_canScrollHorizontally = isPlaceHolderBelowTop && isPlaceHolderBelowBottom;
if (g_canScrollHorizontally) {
containerInViewPort.querySelector('main').scrollLeft += deltaY;
}
}
html,
body {
margin: 0;
font-family: sans-serif;
}
.vertical-section {
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
main {
overflow-x: hidden;
display: flex;
position: sticky;
top: 0;
}
h1 {
margin: 0;
padding: 0;
}
section {
min-width: 100vw;
/*Works perfeclty when it's 50vw*/
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
font-size: 4ch;
}
section:nth-child(even) {
background-color: teal;
color: white;
}
<div class="vertical-section">
Content Before
</div>
<div class="sticky-container">
<main>
<section>
<h1>First</h1>
</section>
<section>
<h1>Second</h1>
</section>
<section>
<h1>Third</h1>
</section>
<section>
<h1>Fourth</h1>
</section>
<section>
<h1>Fifth</h1>
</section>
<section>
<h1>Last</h1>
</section>
</main>
</div>
<div class="vertical-section">
Content After
</div>
You could also iterate over the sections themselves and concatenate their values in a forEach loop.
let stikyContainerHeight = Number();
sec.forEach(s => stikyContainerHeight += s.getBoundingClientRect().width);
main.setAttribute('style', 'height: ' + stikyContainerHeight + 'px');

Apply 1 JS If statement to multiple HTML IDs

This is probably a really simple question and might have been answered before so I may just be phrasing it wrong when I’ve been searching for a solution.
I have a html grid where each <div> will change colour based on the value of a separate input <div>. I have this working so if < 2 - red, >= 3 & < 5 - orange, > 5 - green , but at the moment I am having to duplicate the JS if statement for each "box" I want to add. So the code below has four if statements with the only difference being the number at the end of the ids.
Link to Code Pen: Here
What would I need to change so that I can use one if statement and then in theory add an infinite number of boxes by adding another grid <div> and another input <div> with a different number on the end of the ID name?
<!--Grid-->
<div class="KB-Grid">
<div class="KB-item" id = "KB-1">PC15A </br> Hrs: </div>
<div class="KB-item" id = "KB-2">PC15B </br> Hrs:</div>
<div class="KB-item" id = "KB-3">PC16A </br> Hrs:</div>
<div class="KB-item" id = "KB-4">PC16B </br> Hrs: </div>
</div>
<!--Inputs-->
<div class = "KB-values">
<div id = "KBV1"> 5</div>
<div id = "KBV2"> 5 </div>
<div id = "KBV3"> 5 </div>
<div id = "KBV4"> 5 </div>
</div>
var KBV1 = document.getElementById("KBV1").innerHTML;
if (KBV1 >= 5) {
document.getElementById("KB-1").style.backgroundColor = '#287d00';
} else
if (KBV1 >= 3 && KBV1 < 5) {
document.getElementById("KB-1").style.backgroundColor = '#e0880b';
} else
if (KBV1 <= 2) {
document.getElementById("KB-1").style.backgroundColor = '#ff0000';
}
var KBV2 = document.getElementById("KBV2").innerHTML;
if (KBV2 >= 5) {
document.getElementById("KB-2").style.backgroundColor = '#287d00';
} else
if (KBV2 >= 3 && KBV2 < 5) {
document.getElementById("KB-2").style.backgroundColor = '#e0880b';
} else
if (KBV2 <= 2) {
document.getElementById("KB-2").style.backgroundColor = '#ff0000';
}
var KBV3 = document.getElementById("KBV3").innerHTML;
if (KBV3 >= 5) {
document.getElementById("KB-3").style.backgroundColor = '#287d00';
} else
if (KBV3 >= 3 && KBV3 < 5) {
document.getElementById("KB-3").style.backgroundColor = '#e0880b';
} else
if (KBV3 <= 2) {
document.getElementById("KB-3").style.backgroundColor = '#ff0000';
}
var KBV4 = document.getElementById("KBV4").innerHTML;
if (KBV4 >= 5) {
document.getElementById("KB-4").style.backgroundColor = '#287d00';
} else
if (KBV4 >= 3 && KBV4 < 5) {
document.getElementById("KB-4").style.backgroundColor = '#e0880b';
} else
if (KBV4 <= 2) {
document.getElementById("KB-4").style.backgroundColor = '#ff0000';
}
CSS (not sure if this is need to awnser the question so left it at the bottom)
.KB-Grid {
display: flex;
flex-wrap: wrap;
padding:20px;
}
.KB-item {
height: 80px;
flex-grow: 1;
flex-shrink: 0;
flex-basis: 33.3333%;
flex-basis: 200px;
display: flex;
align-items: center;
justify-content: center;
border: 3px solid;
font-size: 30px;
text-align: center;
font-family: Roboto, arial, san-serif;
}
.blank {
height: 0;
}
.KB-values{
visibility: hidden;
}
Your best bet is to use data-attributes. So add data-target to each div that stores the value, and have that target store the id of the element you want to change the background of.
The one single loop will cover all future data.
values = document.querySelectorAll(".KB-values div");
values.forEach(function(el) {
val = Number(el.innerHTML);
target = document.querySelector(el.dataset.target);
if (val >= 5) {
target.style.backgroundColor = '#287d00';
} else if (val >= 3 && val < 5) {
target.style.backgroundColor = '#e0880b';
} else if (val <= 2) {
target.style.backgroundColor = '#ff0000';
}
});
.KB-Grid {
display: flex;
flex-wrap: wrap;
padding:20px;
}
.KB-item {
height: 80px;
flex-grow: 1;
flex-shrink: 0;
flex-basis: 33.3333%;
flex-basis: 200px;
display: flex;
align-items: center;
justify-content: center;
border: 3px solid;
font-size: 30px;
text-align: center;
font-family: Roboto, arial, san-serif;
}
.blank {
height: 0;
}
.KB-values{
visibility: hidden;
}
<div class="KB-Grid">
<div class="KB-item" id="KB-1">PC15A </br> Hrs: </div>
<div class="KB-item" id="KB-2">PC15B </br> Hrs:</div>
<div class="KB-item" id="KB-3">PC16A </br> Hrs:</div>
<div class="KB-item" id="KB-4">PC16B </br> Hrs: </div>
</div>
<!--Inputs-->
<div class="KB-values">
<div data-target="#KB-1"> 6</div>
<div data-target="#KB-2"> 4 </div>
<div data-target="#KB-3"> 2 </div>
<div data-target="#KB-4"> 1 </div>
</div>

Center horizontally child elements if their parent's width is 300% but each child's width 100%

I have a dynamic slider with two buttons left and right.
that means for each slide, the slide parent width increases by 100%. 2 slides * 100% = 200%. In example class="slider"; width:'200%'
I want to center each slide's text in the middle of the page. But i want the text to slide not in just slides container, but in its parent-parent width (class='carousel' in example).
Code below, is example how the slider is looking right now.
JavaScript, you should ignore this. Implemented it, for the code to work.
document.addEventListener('DOMContentLoaded', function() { //Display function after HTML is loaded
const left = document.querySelector('.left');
const right = document.querySelector('.right');
var slider = document.getElementById('slider');
var leftImg = document.getElementById('left');
var rightImg = document.getElementById('right');
var sections = document.querySelectorAll('.slide').length; // get number of slides
var sectionIndex = 1;
slider.style.width = ' ' + 100 * sections + '%';
function changeOpacity() {
if (sectionIndex == 1) {
leftImg.style.opacity = '0.4';
} else {
leftImg.style.opacity = '1';
}
if (sectionIndex == sections) {
rightImg.style.opacity = '0.4';
} else {
rightImg.style.opacity = '1';
}
}
left.addEventListener('click', function() {
var leftImg = document.getElementById('left');
sectionIndex = (sectionIndex > 1) ? sectionIndex - 1 : 1;
slider.style.transform = 'translate(' + (sectionIndex - 1) * (-100 / sections) + '%)';
changeOpacity();
});
right.addEventListener('click', function() {
sectionIndex = (sectionIndex < sections) ? sectionIndex + 1 : sections;
slider.style.transform = 'translate(' + (sectionIndex - 1) * (-100 / sections) + '%)';
changeOpacity();
});
})
.slider-container {
padding: 25px 0px;
width: 40%;
margin: auto;
}
.slider-container .carousel {
overflow: hidden;
height: 260px;
width: 100%;
border:solid 2px black;
position:relative;
}
.slider-container .slider {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
height: 100%;
-webkit-transition: .5s;
transition: .5s;
}
.slider-container .slider .slide {
width: 100%;
}
.slider-container .arrow-container {
width: 70px;
position: absolute;
bottom: 0;
}
<div class="slider-container mobile-container text-left">
<div class="carousel relative">
<div id="slider" class="slider">
<div class="slide">
<div class="author d-flex flex-column">
<h3>Ken Ludden</h3>
<span class="regularText">Director, Margot Fonteyn Academy of Ballet</span>
</div>
</div>
<div class="slide">
<div class="author d-flex flex-column">
<h3>Ken Ludden</h3>
<span class="regularText">Director, Margot Fonteyn Academy of Ballet</span>
</div>
</div>
</div>
</div>
<div class="controls">
<div class="arrow-container d-flex justify-content-between ">
<div>
<button class="left" id="left" style="opacity: 0.4;">Left </button>
</div>
<div>
<button class="right" id="right">Right</button>
</div>
</div>
</div>
</div>
</div>
The Snippet below is what i want. But i should be centered, and i don't know how.
I have tried using fl
document.addEventListener('DOMContentLoaded', function() { //Display function after HTML is loaded
const left = document.querySelector('.left');
const right = document.querySelector('.right');
var slider = document.getElementById('slider');
var leftImg = document.getElementById('left');
var rightImg = document.getElementById('right');
var sections = document.querySelectorAll('.slide').length; // get number of slides
var sectionIndex = 1;
slider.style.width = ' ' + 100 * sections + '%';
function changeOpacity() {
if (sectionIndex == 1) {
leftImg.style.opacity = '0.4';
} else {
leftImg.style.opacity = '1';
}
if (sectionIndex == sections) {
rightImg.style.opacity = '0.4';
} else {
rightImg.style.opacity = '1';
}
}
left.addEventListener('click', function() {
var leftImg = document.getElementById('left');
sectionIndex = (sectionIndex > 1) ? sectionIndex - 1 : 1;
slider.style.transform = 'translate(' + (sectionIndex - 1) * (-100 / sections) + '%)';
changeOpacity();
});
right.addEventListener('click', function() {
sectionIndex = (sectionIndex < sections) ? sectionIndex + 1 : sections;
slider.style.transform = 'translate(' + (sectionIndex - 1) * (-100 / sections) + '%)';
changeOpacity();
});
})
.slider-container {
margin: auto;
padding: 25px 0px;
}
.slider-container .carousel {
overflow: hidden;
height: 260px;
width: 80%; /* the width i want */
border: solid 2px black; /* the border for your understading */
position: relative;
}
.slider-container .slider {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
height: 100%;
-webkit-transition: .5s;
transition: .5s;
}
.slider-container .slider .slide {
width: 100%;
}
.slider-container .comment {
max-width: 352px;
padding: 30px 0px;
}
.slider-container .arrow-container {
width: 70px;
position: absolute;
bottom: 0;
}
<div class="slider-container mobile-container text-left">
<div class="carousel relative">
<div id="slider" class="slider">
<div class="slide">
<div class="author d-flex flex-column">
<h3>Ken Ludden</h3>
<span class="regularText">Director, Margot Fonteyn Academy of Ballet</span>
</div>
</div>
<div class="slide">
<div class="author d-flex flex-column">
<h3>Ken Ludden</h3>
<span class="regularText">Director, Margot Fonteyn Academy of Ballet</span>
</div>
</div>
</div>
<div class="controls">
<div class="arrow-container d-flex justify-content-between ">
<div>
<button class="left" id="left" style="opacity: 0.4;">Left </button>
</div>
<div>
<button class="right" id="right">Right</button>
</div>
</div>
</div>
</div>
</div>
</div>
You can see in this snippet that text is sliding from a lot further right than the previous example.
I need to center the slide, because i want the same for left side.
I have tried using flex-column, align-items:center on class="slide". And it works fine, but the class="controls" aren't centering because they are position:absolute and i tried to putting them elsewhere, but it didnt work..
I really hope you guys did understand what i want and really hope that i recieve atleast some suggestions. This is my 1st question, sorry for long code.
Thank you anyway :)
Your carousel is 80% of the width, so if you want that to be centered, you can do: margin: 0 auto on the carousel class.

Adapt vanilla js carousel to ie

I'm building a website that uses a carousel like this one:
https://codepen.io/queflojera/pen/RwwLbEY?editors=1010
It works perfectly on opera, chrome, edge but it stops working on ie and I need it to work on ie as well, if anyone knows any way around I'll really appreciate it.
//I'm not pretty sure what is causing the ie failure on this code
// Select the carousel you'll need to manipulate and the buttons you'll add events to
const carousel = document.querySelector("[data-target='carousel']");
const card = carousel.querySelector("[data-target='card']");
const leftButton = document.querySelector("[data-action='slideLeft']");
const rightButton = document.querySelector("[data-action='slideRight']");
// Prepare to limit the direction in which the carousel can slide,
// and to control how much the carousel advances by each time.
// In order to slide the carousel so that only three cards are perfectly visible each time,
// you need to know the carousel width, and the margin placed on a given card in the carousel
const carouselWidth = carousel.offsetWidth;
const cardStyle = card.currentStyle || window.getComputedStyle(card)
const cardMarginRight = Number(cardStyle.marginRight.match(/\d+/g)[0]);
// Count the number of total cards you have
const cardCount = carousel.querySelectorAll("[data-target='card']").length;
// Define an offset property to dynamically update by clicking the button controls
// as well as a maxX property so the carousel knows when to stop at the upper limit
let offset = 0;
const maxX = -((cardCount) * carouselWidth +
(cardMarginRight * cardCount) -
carouselWidth - cardMarginRight);
// Add the click events
leftButton.addEventListener("click", function() {
if (offset !== 0) {
offset += carouselWidth + cardMarginRight;
carousel.style.transform = `translateX(${offset}px)`;
}
})
rightButton.addEventListener("click", function() {
if (offset !== maxX) {
offset -= carouselWidth + cardMarginRight;
carousel.style.transform = `translateX(${offset}px)`;
}
})
.wrapper {
height: 200px;
width: 632px;
position: relative;
overflow: hidden;
margin: 0 auto;
}
.button-wrapper {
width: 100%;
height: 100%;
display: flex;
justify-content: space-between;
align-items: center;
position: absolute;
}
.carousel {
margin: 0;
padding: 0;
list-style: none;
width: 100%;
display: flex;
position: absolute;
left: 0;
transition: all .5s ease;
}
.card {
background: black;
min-width: 632px;
height: 200px;
display: inline-block;
}
.card:nth-child(odd) {
background-color: blue;
}
.card:nth-child(even) {
background-color: red;
}
<div class="wrapper">
<ul class="carousel" data-target="carousel">
<li class="card" data-target="card">1</li>
<li class="card" data-target="card">2</li>
<li class="card" data-target="card">3</li>
<li class="card" data-target="card">4</li>
<li class="card" data-target="card">5</li>
<li class="card" data-target="card">6</li>
<li class="card" data-target="card">7</li>
<li class="card" data-target="card">8</li>
<li class="card" data-target="card">9</li>
</ul>
<div class="button-wrapper">
<button data-action="slideLeft">L</button>
<button data-action="slideRight">R</button>
</div>
</div>
Invalid character
carousel.style.transform = `translateX(${offset}px)`;
IE does not support template literals (backticks)
To fix use
carousel.style.transform = "translateX("+offset+"px)";
Also getting
Unable to get property '0' of undefined or null reference
because it is auto in IE
const cardMarginRight = Number(cardStyle.marginRight.match(/\d+/g)[0]);
Fix:
const marginRight = cardStyle.marginRight;
const cardMarginRight = isNaN(parseInt(marginRight)) ? 0 : Number(cardStyle.marginRight.match(/\d+/g)[0]);
//I'm not pretty sure what is causing the ie failure on this code
// Select the carousel you'll need to manipulate and the buttons you'll add events to
const carousel = document.querySelector("[data-target='carousel']");
const card = carousel.querySelector("[data-target='card']");
const leftButton = document.querySelector("[data-action='slideLeft']");
const rightButton = document.querySelector("[data-action='slideRight']");
// Prepare to limit the direction in which the carousel can slide,
// and to control how much the carousel advances by each time.
// In order to slide the carousel so that only three cards are perfectly visible each time,
// you need to know the carousel width, and the margin placed on a given card in the carousel
const carouselWidth = carousel.offsetWidth;
const cardStyle = card.currentStyle || window.getComputedStyle(card)
const marginRight = cardStyle.marginRight;
const cardMarginRight = isNaN(parseInt(marginRight)) ? 0 : Number(cardStyle.marginRight.match(/\d+/g)[0]);
// Count the number of total cards you have
const cardCount = carousel.querySelectorAll("[data-target='card']").length;
// Define an offset property to dynamically update by clicking the button controls
// as well as a maxX property so the carousel knows when to stop at the upper limit
let offset = 0;
const maxX = -((cardCount) * carouselWidth +
(cardMarginRight * cardCount) -
carouselWidth - cardMarginRight);
// Add the click events
leftButton.addEventListener("click", function() {
if (offset !== 0) {
offset += carouselWidth + cardMarginRight;
carousel.style.transform = "translateX("+offset+"px)";
}
})
rightButton.addEventListener("click", function() {
if (offset !== maxX) {
offset -= carouselWidth + cardMarginRight;
carousel.style.transform = "translateX("+offset+"px)";
}
})
.wrapper {
height: 200px;
width: 632px;
position: relative;
overflow: hidden;
margin: 0 auto;
}
.button-wrapper {
width: 100%;
height: 100%;
display: flex;
justify-content: space-between;
align-items: center;
position: absolute;
}
.carousel {
margin: 0;
padding: 0;
list-style: none;
width: 100%;
display: flex;
position: absolute;
left: 0;
transition: all .5s ease;
}
.card {
background: black;
min-width: 632px;
height: 200px;
display: inline-block;
}
.card:nth-child(odd) {
background-color: blue;
}
.card:nth-child(even) {
background-color: red;
}
<div class="wrapper">
<ul class="carousel" data-target="carousel">
<li class="card" data-target="card">1</li>
<li class="card" data-target="card">2</li>
<li class="card" data-target="card">3</li>
<li class="card" data-target="card">4</li>
<li class="card" data-target="card">5</li>
<li class="card" data-target="card">6</li>
<li class="card" data-target="card">7</li>
<li class="card" data-target="card">8</li>
<li class="card" data-target="card">9</li>
</ul>
<div class="button-wrapper">
<button data-action="slideLeft">L</button>
<button data-action="slideRight">R</button>
</div>
</div>

Categories