Issue
I was making a horizontally scrollable grid, I set overflow-x: scroll;
and added two arrows. I added an event listener to both arrows to detect clicks and then scroll the grid, but the DOMElement.scroll(options)
function is not working, the grid is not scrolled and the scroll
event on the DOMElement
is not fired.
const vwToPx = (vw) => document.documentElement.clientWidth * vw / 100;
const scrollingArrows = document.querySelectorAll(".scroll-arrow");
scrollingArrows.forEach(arrow => {
const parentGrid = arrow.parentElement;
parentGrid.addEventListener("scroll", () => console.log("scroll")) // Callback not invoked which means that the scroll() method is not working
arrow.addEventListener("click", () => {
const scrollLength = vwToPx(30) * 3 * (arrow.classList.contains("back-arrow") ? -1 : 1);
console.log(parentGrid.scrollLeft, scrollLength)
parentGrid.scroll({
left: parentGrid.scrollLeft + scrollLength,
behavior: "smooth"
});
console.log("scrolled") // Logs so the click callback is correctly set up which means that the scroll() method is not working
})
})
.cards-grid-wrapper {
position: relative;
}
.cards-grid {
width: 100%;
display: grid;
grid-auto-columns: 30vw;
grid-auto-flow: column;
gap: 2vw;
overflow-x: scroll;
scrollbar-width: none;
}
.cards-grid::-webkit-scrollbar {
display: none;
}
.scroll-arrow {
width: 4vw;
height: 4vw;
background-color: var(--light-black);
position: absolute;
bottom: calc(150px / 2 + 15px);
background-repeat: no-repeat;
background-size: 30px;
background-position: center;
border-radius: 100%;
display: flex;
align-items: center;
justify-content: center;
font-family: "Material icons";
font-weight: 900;
font-size: 30px;
cursor: pointer;
box-shadow: black 0 0 5px;
}
.back-arrow {
background-image: url(/images/icons/back-arrow.svg);
left: -2vw;
place-self: center start;
}
.forward-arrow {
background-image: url(/images/icons/forward-arrow.svg);
right: -2vw;
place-self: center end;
}
.cards-grid .card {
height: 150px;
background-color: var(--light-black);
padding: 2vw;
margin-bottom: 15px;
border-radius: 5px;
cursor: pointer;
transition: 0.3s;
}
.cards-grid .card:hover {
background-color: var(--hover-light-black);
box-shadow: black 0px 5px 15px;
transition: 0.3s;
}
.cards-grid .card * {
margin: 0;
}
.cards-grid .card h1 {
font-size: 20px;
font-weight: 600;
margin-bottom: 0.5rem;
}
<div class="cards-grid-wrapper">
<div class="scroll-arrow back-arrow"></div>
<div class="scroll-arrow forward-arrow"></div>
<div class="cards-grid">
<div class="card">
<h1>Title</h1>
<p>Content</p>
</div>
<div class="card">
<h1>Title</h1>
<p>Content</p>
</div>
<div class="card">
<h1>Title</h1>
<p>Content</p>
</div>
<div class="card">
<h1>Title</h1>
<p>Content</p>
</div>
<div class="card">
<h1>Title</h1>
<p>Content</p>
</div>
<div class="card">
<h1>Title</h1>
<p>Content</p>
</div>
<div class="card">
<h1>Title</h1>
<p>Content</p>
</div>
</div>
</div>
Solution
If you attach the scroll
function to the .cards-grid
element rather than the parent container ( it is, after all, the .cards-grid
container that has overflow-x: scroll;
) and calculate the offset based upon that element it works?
The below uses a delegated listener bound to the parent .cards-grid-wrapper
element rather than individual event listeners
const vwToPx=(vw)=>document.documentElement.clientWidth * vw / 100;
const wrapper=document.querySelector('.cards-grid-wrapper');
const grid=wrapper.querySelector('.cards-grid');
wrapper.addEventListener('click',e=>{
if( e.target.classList.contains('scroll-arrow') ){
let dir=( e.target.classList.contains('back-arrow') ) ? -1 : 1;
let slen=vwToPx( 30 ) * 3 * dir;
grid.scroll({
left:grid.scrollLeft + slen,
behaviou:'smooth'
})
}
});
grid.addEventListener('scroll',e=>{
console.log(e.type)
});
body{
counter-card:reset;
}
.cards-grid-wrapper {
position: relative;
}
.cards-grid {
width: 100%;
display: grid;
grid-auto-columns: 30vw;
grid-auto-flow: column;
gap: 2vw;
overflow-x: scroll;
scrollbar-width: none;
}
.cards-grid::-webkit-scrollbar {
display: none;
}
.scroll-arrow {
width: 4vw;
height: 4vw;
background-color: var(--light-black);
position: absolute;
bottom: calc(150px / 2 + 15px);
background-repeat: no-repeat;
background-size: 30px;
background-position: center;
border-radius: 100%;
display: flex;
align-items: center;
justify-content: center;
font-family: "Material icons";
font-weight: 900;
font-size: 30px;
cursor: pointer;
box-shadow: black 0 0 5px;
}
.back-arrow {
background-image: url(/images/icons/back-arrow.svg);
left: -2vw;
place-self: center start;
}
.forward-arrow {
background-image: url(/images/icons/forward-arrow.svg);
right: -2vw;
place-self: center end;
}
.cards-grid .card {
height: 150px;
background-color: var(--light-black);
padding: 2vw;
margin-bottom: 15px;
border-radius: 5px;
cursor: pointer;
transition: 0.3s;
}
.cards-grid .card:hover {
background-color: var(--hover-light-black);
box-shadow: black 0px 5px 15px;
transition: 0.3s;
}
.cards-grid .card * {
margin: 0;
}
.cards-grid .card h1 {
font-size: 20px;
font-weight: 600;
margin-bottom: 0.5rem;
}
.card{
counter-increment:card;
}
.card:nth-of-type(odd){
background:pink;
}
.card h1:after{
content:counter(card)
}
<div class="cards-grid-wrapper">
<div class="scroll-arrow back-arrow"></div>
<div class="scroll-arrow forward-arrow"></div>
<div class="cards-grid">
<div class="card">
<h1>Title</h1>
<p>Content</p>
</div>
<div class="card">
<h1>Title</h1>
<p>Content</p>
</div>
<div class="card">
<h1>Title</h1>
<p>Content</p>
</div>
<div class="card">
<h1>Title</h1>
<p>Content</p>
</div>
<div class="card">
<h1>Title</h1>
<p>Content</p>
</div>
<div class="card">
<h1>Title</h1>
<p>Content</p>
</div>
<div class="card">
<h1>Title</h1>
<p>Content</p>
</div>
<div class="card">
<h1>Title</h1>
<p>Content</p>
</div>
<div class="card">
<h1>Title</h1>
<p>Content</p>
</div>
<div class="card">
<h1>Title</h1>
<p>Content</p>
</div>
<div class="card">
<h1>Title</h1>
<p>Content</p>
</div>
<div class="card">
<h1>Title</h1>
<p>Content</p>
</div>
<div class="card">
<h1>Title</h1>
<p>Content</p>
</div>
<div class="card">
<h1>Title</h1>
<p>Content</p>
</div>
</div>
</div>
Answered By - Professor Abronsius
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.