I have 3 blocks, the second block has a line and a scrolling circle. The circle will scroll along with the main scroll, and when the scroll stops, the circle sticks to the nearest point, which is in the center of each block
But I have such a problem here, when the main scroll crosses the second block, the circle stops scrolling and behaves incorrectly on the page
Is it possible to complete the script so that when the main scroll crosses block2, the circle will automatically stick to the last case and stop scrolling at all? And when we rise back and cross block2, then, accordingly, it should work again
In general, the problem is with the last case, when the scroll reaches it, the circle does not move further, maybe there is another option how to fix it, and not the one I suggested
const circle = document.querySelector(".circle");
const cases = document.querySelectorAll(".case");
let timer = null;
const detectCase = () => {
const circleCenter = circle.offsetTop + circle.offsetHeight / 2;
let activeCase = null,
minDist = Infinity;
cases.forEach((elem) => {
const caseCenter = elem.offsetTop + elem.offsetHeight / 2;
const dist = Math.abs(caseCenter - circleCenter);
if (dist < minDist) {
minDist = dist;
activeCase = elem;
}
});
return activeCase;
};
const handleScroll = () => {
const {
height: blockHeight
} = document.querySelector(".block2").getBoundingClientRect();
const maxTop = cases[cases.length - 1].offsetTop;
const minTop = cases[0].offsetTop;
let {
height: startTop
} = cases[0].getBoundingClientRect();
let scrollDist = startTop / 2 + window.scrollY;
scrollDist = scrollDist > maxTop ? maxTop : scrollDist < minTop ? minTop : scrollDist;
circle.style.top = `${scrollDist}px`;
circle.style.backgroundSize = `15px ${blockHeight}px`;
circle.style.backgroundPosition = `0 ${-scrollDist}px`;
if (timer) return;
timer = setTimeout(() => {
const active = detectCase();
const activePos = active.offsetTop + active.offsetHeight / 2;
circle.style.top = `${activePos}px`;
circle.style.backgroundPosition = `0 ${-activePos}px`;
circle.style.transition = "0.5s";
timer = null;
}, 800);
circle.style.transition = "";
};
const handleWindowSize = () => {
if (window.innerWidth >= 991) {
window.addEventListener("scroll", handleScroll);
window.addEventListener("resize", handleScroll);
} else {
window.removeEventListener("scroll", handleScroll);
window.removeEventListener("resize", handleScroll);
}
};
handleScroll();
handleWindowSize();
window.addEventListener("resize", handleWindowSize);
.block1 {
height: 200px;
background-color: gray;
}
.block3 {
height: 600px;
background-color: gray;
}
.block2 {
height: 100%;
position: relative;
}
.block2,
.block2 .circle {
background: linear-gradient(214deg, rgba(79, 142, 255, 0) 0%, #4f8eff 10%, #f5e550 90%, rgba(79, 142, 255, 0) 100%) center/3px calc(100% - 100px) no-repeat;
}
.block2 .circle {
width: 15px;
height: 15px;
left: calc(50% - 8px);
}
.block2 .circle,
.block2 .circle::before {
position: absolute;
border-radius: 50%;
}
.block2 .circle::before {
content: "";
inset: 3px;
background-color: white;
}
.text {
text-align: center;
padding: 200px 50px;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/css/bootstrap.min.css" integrity="sha512-t4GWSVZO1eC8BM339Xd7Uphw5s17a86tIZIj8qRxhnKub6WoyhnrxeCIMeAqBPgdZGlCcG2PrZjMc+Wr78+5Xg==" crossorigin="anonymous" referrerpolicy="no-referrer"
/>
<div class="block1"></div>
<div class="block2">
<div class="circle"></div>
<div class="case">
<div class="row">
<div class="col-5 text">Text 1</div>
<div class="col-2"></div>
<div class="col-5 text">Text 1</div>
</div>
</div>
<div class="case">
<div class="row">
<div class="col-5 text">Text 2</div>
<div class="col-2"></div>
<div class="col-5 text">Text 2</div>
</div>
</div>
<div class="case">
<div class="row">
<div class="col-5 text">Text 3</div>
<div class="col-2"></div>
<div class="col-5 text">Text 3</div>
</div>
</div>
</div>
<div class="block3"></div>from stop the scroll line from scrolling if the block is crossed
No comments:
Post a Comment