LERP Smooth Scrolling

戏子无情 提交于 2020-12-15 01:42:22

问题


I have been wanting to implement smooth scrolling in vanilla JS for some time, but could not find any adequate implementations or methods. However, I recently came across the concept of linear interpolation (LERP), which seems adequate unlike every other method.

Although content about LERP smooth scrolling seems scarce on the web, I just found two great articles (one, two) about LERP in general and an example of LERP being used for smooth scrolling on codepen.

The example, notably, seems unnecessarily complex due to a seemingly unnecessary amount of nested containers, so I created a minimal version of it shown below. The minimal version seems to be working, but I still have a few concerns and questions.

const
  b = document.body,
  m = document.querySelector('main'),
  p = document.querySelector('p')

let
  state = {
    scroll: {
      height: 0,
      offset: 0,
      speed: 0.075,
    }
  },
  direction

document.addEventListener('DOMContentLoaded', () => {
  state.scroll.height = m.getBoundingClientRect().height
  b.style.height = `${Math.floor(state.scroll.height)}px`
})

b.addEventListener('wheel', (e) => {
  direction = e.deltaY > 0 ? 'scrollDown' : 'scrollUp'
  // renderLoop()
})

function renderLoop() {
  // const
  //   difference = 'scrollDown' ? pageYOffset - state.scroll.offset : state.scroll.offset - pageYOffset
  state.scroll.offset += Math.floor((pageYOffset - state.scroll.offset) * state.scroll.speed)
  m.style.transform = `translateY(-${ state.scroll.offset }px)`
  // if (difference > 20) requestAnimationFrame(renderLoop)
  requestAnimationFrame(renderLoop)
}

renderLoop()
html, body {
  width: 100%;
  height: 100%;
  margin: 0;
  font-size: 48px;
}

main {
  width: 100%;
  position: fixed;
  left: 0;
  top: 0;
border: solid green 3px; box-sizing: border-box;
}

p {
  width: 100%;
  max-width: 500px;
  position: relative;
  left: 50%;
  transform: translateX(-50%);
  margin: 0;
border: solid red 3px; box-sizing: border-box;
}
<main>
  <p>One<br>Lorem ipsum dolor sit amet consectetur, adipisicing elit. Error soluta, quidem voluptatibus quo iusto iure adipisci, ullam quis unde dolore, nisi impedit in. Veniam, suscipit? Atque aut et incidunt aliquid. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Exercitationem labore dolore aut atque harum, quo necessitatibus molestias laborum fuga beatae explicabo laudantium asperiores doloremque optio iure, assumenda voluptate unde voluptates? Lorem ipsum dolor sit amet consectetur adipisicing elit. Amet inventore, voluptates corrupti illo impedit in. Recusandae, praesentium temporibus tempore totam cupiditate ratione maxime numquam corporis repudiandae. Veniam ullam rerum quo?</p>
  <p>Two<br>Lorem ipsum dolor sit amet consectetur, adipisicing elit. Error soluta, quidem voluptatibus quo iusto iure adipisci, ullam quis unde dolore, nisi impedit in. Veniam, suscipit? Atque aut et incidunt aliquid. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Exercitationem labore dolore aut atque harum, quo necessitatibus molestias laborum fuga beatae explicabo laudantium asperiores doloremque optio iure, assumenda voluptate unde voluptates? Lorem ipsum dolor sit amet consectetur adipisicing elit. Amet inventore, voluptates corrupti illo impedit in. Recusandae, praesentium temporibus tempore totam cupiditate ratione maxime numquam corporis repudiandae. Veniam ullam rerum quo?</p>
  <p>Three<br>Lorem ipsum dolor sit amet consectetur, adipisicing elit. Error soluta, quidem voluptatibus quo iusto iure adipisci, ullam quis unde dolore, nisi impedit in. Veniam, suscipit? Atque aut et incidunt aliquid. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Exercitationem labore dolore aut atque harum, quo necessitatibus molestias laborum fuga beatae explicabo laudantium asperiores doloremque optio iure, assumenda voluptate unde voluptates? Lorem ipsum dolor sit amet consectetur adipisicing elit. Amet inventore, voluptates corrupti illo impedit in. Recusandae, praesentium temporibus tempore totam cupiditate ratione maxime numquam corporis repudiandae. Veniam ullam rerum quo?</p>
</main>

One concern is that for some reason it breaks unless I call renderLoop from the global scope and let requestAnimationFrame run indefinitely without a killswitch, which, instinctively, does not seem like a good idea?

I am also confused by the fact that, although I am offsetting the content container via translate, there still appears to be a scrollbar that scrolls. And yet, notably, this does not appear to interfere with the effect at all. However, should LERP smooth scrolling via translate not bypass scrollbars and scrolling altogether?

Additionally, it seems as though the only purpose of setting the height of body to that of main is to make use of pageYOffset. I suspect there are better ways to approach the problem that do not involve using pageYOffset. Further, you would think that the combination of offsetting with translate and the page being scrolled would increase the rate at which the content is scrolled?

Anyways, I have just started coding again after an almost year-long absence, and I am not sure if I ever familiarized myself with requestAnimationFrame, so any information, guidance, or solutions would be greatly appreciated.

[ edit + update ]

Here is a codepen of a "working" (?) version, which can be seen below, that I created in attempt to address and solve some concerns or issues present in the version above. However, it clearly does not have the same effect due to, I believe, the offset value being a percentage instead of pixels, which was chosen in an attempt to standardize the "speed" at which it scrolls across "platforms" (i.e. devices, browsers, etc).

const
  b = document.body,
  m = document.querySelector('main')

let
  scrollState = {
    overflow: 0,
    target: 0,
    position: 0,
    rate: 10,
    speed: 0.2
  }

b.addEventListener('wheel', (e) => {
  scrollState.target -= scrollState.rate * (e.deltaY / 100)
  if (scrollState.target > 0) scrollState.target = 0
  else if (scrollState.target < -100) scrollState.target = -100
  renderLoop()
})

function renderLoop() {
  const
    rawDiff = Math.abs(scrollState.position - scrollState.target),
    direction = scrollState.position - scrollState.target < 0 ? -1 : 1,
    diff = rawDiff * scrollState.speed * direction,
    newPosition = scrollState.position - diff

  m.style.transform = `translateY(${newPosition}%)`
  scrollState.position = newPosition
  if (Math.floor(rawDiff)) requestAnimationFrame(renderLoop)
}
html, body {
  width: 100%;
  height: 100%;
  margin: 0;
  font-size: 48px;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

body {
border: solid blue 4px; box-sizing: border-box;
}

main {
  width: 100%;
  position: fixed;
  left: 0;
  top: 0;
border: solid green 2px; box-sizing: border-box;
}

p {
  width: 100%;
  max-width: 500px;
  position: relative;
  left: 50%;
  transform: translateX(-50%);
  margin: 0;
border: solid red 2px; box-sizing: border-box;
}
<main>
  <p>One<br>Lorem ipsum dolor sit amet consectetur, adipisicing elit. Error soluta, quidem voluptatibus quo iusto iure adipisci, ullam quis unde dolore, nisi impedit in. Veniam, suscipit? Atque aut et incidunt aliquid. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Exercitationem labore dolore aut atque harum, quo necessitatibus molestias laborum fuga beatae explicabo laudantium asperiores doloremque optio iure, assumenda voluptate unde voluptates? Lorem ipsum dolor sit amet consectetur adipisicing elit. Amet inventore, voluptates corrupti illo impedit in. Recusandae, praesentium temporibus tempore totam cupiditate ratione maxime numquam corporis repudiandae. Veniam ullam rerum quo?</p>
  <p>Two<br>Lorem ipsum dolor sit amet consectetur, adipisicing elit. Error soluta, quidem voluptatibus quo iusto iure adipisci, ullam quis unde dolore, nisi impedit in. Veniam, suscipit? Atque aut et incidunt aliquid. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Exercitationem labore dolore aut atque harum, quo necessitatibus molestias laborum fuga beatae explicabo laudantium asperiores doloremque optio iure, assumenda voluptate unde voluptates? Lorem ipsum dolor sit amet consectetur adipisicing elit. Amet inventore, voluptates corrupti illo impedit in. Recusandae, praesentium temporibus tempore totam cupiditate ratione maxime numquam corporis repudiandae. Veniam ullam rerum quo?</p>
  <p>Three<br>Lorem ipsum dolor sit amet consectetur, adipisicing elit. Error soluta, quidem voluptatibus quo iusto iure adipisci, ullam quis unde dolore, nisi impedit in. Veniam, suscipit? Atque aut et incidunt aliquid. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Exercitationem labore dolore aut atque harum, quo necessitatibus molestias laborum fuga beatae explicabo laudantium asperiores doloremque optio iure, assumenda voluptate unde voluptates? Lorem ipsum dolor sit amet consectetur adipisicing elit. Amet inventore, voluptates corrupti illo impedit in. Recusandae, praesentium temporibus tempore totam cupiditate ratione maxime numquam corporis repudiandae. Veniam ullam rerum quo?</p>
</main>

来源:https://stackoverflow.com/questions/64872594/lerp-smooth-scrolling

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!