I making scroll animation progress bars, when the scroll reaches the element's width change from 0 to 78%. but there is one problem whenever I scroll again in the same height condition my width reset. I know why this happens. in fact, the range variable(i comment in JS) reassigns to 0 whenever I scroll, I don't know how to fix it. I read about Closures but couldn't understand how I must apply that to my code thanks for reading and for your time
//my js code
const SEORange = document.getElementById("SEO");
window.addEventListener("scroll", () => {
let top = SEORange.getBoundingClientRect().top;
let range = 0; // the problem is here range will be reset
//whenever I scroll
if (top < window.innerHeight * 0.905) {
setInterval(() => {
if (range == 78) {
clearInterval;
} else {
range ;
SEORange.style.width = range "%";
}
}, 10);
}
});
/*css file*/
*{
height:100vh /*I add some height to see what happen if scroll*/
}
#section2-text-container {
justify-content: end;
flex-basis: 50%;
margin-top: 5%;
}
#section2-text-container form {
margin-top: 10%;
}
.range-container {
background-color: #000000;
border-radius: 0 10px 10px 0;
width: 90%;
height: 8px;
position: relative;
}
#section2-text-container input {
appearance: none;
-webkit-appearance: none;
background-color: #64bfd2;
width: 0;
height: 4px;
margin: 0 5% 0 0;
position: absolute;
inset: 0 0 0 0;
}
#section2-text-container input::-webkit-slider-thumb {
appearance: none;
-webkit-appearance: none;
width: 0px;
background: #010101;
height: 0px;
}
#section2-text-container input::-moz-range-thumb {
width: 0px;
background: #04aa6d;
}
<!--html file-->
<!DOCTYPE html>
<html>
<body>
<div id="section2-text-container">
<form>
<label for="SEO">SEO</label><br><br>
<div >
<input id="SEO" disabled type="range" value="0" />
</div>
</form>
</div>
</body>
</html>
CodePudding user response:
First you have to make sure that you clear the interval, because 'scroll' event will be fired multiple times each second when the user scrolls.
const SEORange = document.getElementById("SEO");
let intervalId;
let range = 0;
window.addEventListener("scroll", () => {
let top = SEORange.getBoundingClientRect().top;
// If intervalId is set, it means the code has been ran once.
if (top < window.innerHeight * 0.905 && !intervalId) {
intervalId = setInterval(() => {
if (range === 78) {
clearInterval(intervalId);
} else {
range ;
SEORange.style.width = range "%";
}
}, 10);
}
})
Another solution would be to add a class to trigger the transition you want. Which is IMO way better(smoother) than setting the width using an interval.
const SEORange2 = document.getElementById("SEO2");
window.addEventListener("scroll", () => {
let top = SEORange.getBoundingClientRect().top;
if (top < window.innerHeight * 0.905) {
SEORange2.classList.add("animate");
}
});
#SEO2 {
height: 30px;
width: 0;
background-color: yellow;
transition: width 780ms linear;
}
#SEO2.animate {
width: 78%;
}
CodePudding user response:
here I tried for 3 elements in one block of code. if anybody has a shorter solution share it with me by helping @c0m1t
const eagerToLearnRange = document.getElementById("eager-to-learn");
const frontEndRange = document.getElementById("front-end");
const SEORange = document.getElementById("SEO");
let intervalId;
window.addEventListener("scroll", () => {
let top = SEORange.getBoundingClientRect().top;
let range = 0;
if (top < window.innerHeight * 0.905 && !intervalId) {
intervalId = setInterval(() => {
if (range <= 20) {
range ;
SEORange.style.width = range "%";
frontEndRange.style.width = range "%";
eagerToLearnRange.style.width = range "%";
} else if (65 >= range && range >= 20) {
frontEndRange.style.width = range "%";
eagerToLearnRange.style.width = range "%";
range ;
} else if (65 <= range && range <= 100) {
eagerToLearnRange.style.width = range "%";
range ;
} else if (range === 100) {
clearInterval(intervalId);
}
}, 10);
}
});
* { height:200vh /*add some height to show you effect */
}
#section2-text-container form {
margin-top: 10%;
}
.range-container {
background-color: #000000;
border-radius: 0 10px 10px 0;
width: 90%;
height: 8px;
position: relative;
}
#section2-text-container input {
appearance: none;
-webkit-appearance: none;
background-color: #64bfd2;
width: 0;
height: 4px;
margin: 0 5% 0 0;
position: absolute;
inset: 0 0 0 0;
}
#section2-text-container input::-webkit-slider-thumb {
appearance: none;
-webkit-appearance: none;
width: 0px;
height: 0px;
}
#section2-text-container input::-moz-range-thumb {
width: 0px;
height: 0px;
}
<DOCTYPE html>
<html>
<body>
<div id="section2-text-container">
<form>
<label for="eager-to-learn">eager to learn</label> <br/><br/>
<div >
<input id="eager-to-learn" disabled type="range" value="0" >
</div>
<br><br>
<label for="front-end">front-end</label><br><br>
<div >
<input id="front-end" disabled type="range" value="0"/>
</div>
<br><br>
<label for="SEO">SEO</label>
<br><br>
<div >
<input id="SEO" disabled type="range" value="0"/>
</div>
</form>
</div>
</body>
</html>