skip to Main Content

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 class="range-container">
          <input id="SEO" disabled type="range" value="0" />
         </div>
        </form>
        
     </div>
</body>
</html>

2

Answers


  1. Chosen as BEST ANSWER

    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 class="range-container">
               <input id="eager-to-learn" disabled type="range" value="0" >
             </div>
     <br><br>
             <label for="front-end">front-end</label><br><br>
              <div class="range-container">
                <input id="front-end" disabled type="range" value="0"/>
              </div>
     <br><br>
              <label for="SEO">SEO</label>
    <br><br>
              <div class="range-container">
                <input id="SEO" disabled type="range" value="0"/>
             </div>
        </form>
      </div>
    </body>
    </html>


  2. 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%;
    }
    

    codesandbox

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search