Smooth Scroll using vanilla javascript

by Raj Shekhar

HTML

<a class="smooth-scroll" href="#goal">Scroll To First Goal</a>
<a class="smooth-scroll" href="#goal-2">Scroll To Second Goal</a>

CSS

.goal {
  background-color: tomato;
  color: white;
}

JavaScript

// Create dummy text and anchor targets
for (let i = 0; i < 100; i++) {
  const element = document.createElement('h1')
  element.innerText = `Hello ${i} World`
  document.body.appendChild(element)
  if (i === 30) {
    const targetElement = document.createElement('h1')
    targetElement.innerText = 'First Goal'
    targetElement.id = 'goal'
    targetElement.classList.add('goal')
    document.body.appendChild(targetElement)
  }
  if (i === 90) {
    const targetElement = document.createElement('h1')
    targetElement.innerText = 'Second Goal'
    targetElement.id = 'goal-2'
    targetElement.classList.add('goal')
    document.body.appendChild(targetElement)
  }
}

// Initialize anchor events
document.querySelectorAll('.smooth-scroll').forEach(anchor => {
  anchor.onclick = (e) => {
    e.preventDefault()
    const href = anchor.getAttribute('href')
    const target = document.querySelector(href)
    const to = target.offsetTop
    scrollTo(document.documentElement, to, 2000)
  }
})

const scrollTo = (element, to, duration) => {
  let start = element.offsetTop
  let change = to - start
  let currentTime = 0
  let increment = 20;


  const animateScroll = () => {
    currentTime += increment;
    const val = easeInOutQuad(currentTime, start, change, duration);
    element.scrollTop = val;
    if (currentTime < duration) {
      setTimeout(animateScroll, increment);
    }
  }

  animateScroll()
}


// Easing function -> easeInOutQuad
// 
//t = current time
//b = start value
//c = change in value
//d = duration
const easeInOutQuad = (t, b, c, d) => {
  t /= d / 2
  if (t < 1) return c / 2 * t * t + b
  t--
  return -c / 2 * (t * (t - 2) - 1) + b
}