'Smooth scroll using translateY in js
I created class based functions in my project. Scroll class is to create smooth scroll behaviour using translateY property. The second one called SideNavigation generate bullet list navigation based on projects elements length. I want to achive smooth scroll effect also on click on those bullets, but can't find solution for this. Code snippet included. Hope anyone can help with this.
const config = {
ease: 0.1,
current: 0,
previous: 0,
rounded: 0
}
class Scroll {
constructor(velocity) {
this.velocity = velocity
}
setBodyHeight() {
document.body.style.height = document.getElementById('projects').getBoundingClientRect().height + 'px'
}
isMobile() {
return 'ontouchstart' in document.documentElement && navigator.userAgent.match(/Mobi/)
}
onScroll() {
config.current = window.scrollY
config.previous += (config.current - config.previous) * config.ease
config.rounded = Math.round(config.previous * 100) / 100
const difference = config.current - config.rounded
const acceleration = difference / document.body.clientWidth
const velocity = +acceleration
const skew = velocity * this.velocity
const element = document.getElementById('projects')
this.isMobile() ? element.style.transform = `skewY(${skew}deg)` : element.style.transform = `translateY(-${config.rounded}px)`
requestAnimationFrame(() => this.onScroll())
}
}
class SideNavigation {
constructor() {
createBullets()
}
}
function createBullets() {
const bulletWrapper = document.createElement('div')
const bulletList = document.createElement('ul')
bulletWrapper.classList.add('side-nav')
for (let i = 0; i < document.getElementsByClassName('project').length; i++) {
const bullet = document.createElement('li')
bullet.setAttribute('id', '' + i)
bullet.addEventListener('click', event => {
console.log(document.getElementsByClassName('project')[parseInt(event.target.id)].offsetTop)
// scroll to current section
})
bulletList.append(bullet)
bulletWrapper.append(bulletList)
document.body.append(bulletWrapper)
}
}
window.addEventListener('load', () => {
const scrollInstance = new Scroll(8, true)
const sideNav = new SideNavigation()
scrollInstance.setBodyHeight()
requestAnimationFrame(() => scrollInstance.onScroll())
})
html,
body {
height: 100%;
}
main {
position: fixed;
left: 0;
top: 0;
height: 100%;
width: 100%;
overflow: hidden;
}
#projects {
width: 80%;
}
.project {
height: 500px;
width: 100%;
background: #333;
color: #fff;
}
.side-nav {
position: fixed;
right: 20px;
top: 20%;
z-index: 10;
}
.side-nav li {
width: 30px;
height: 30px;
display: block;
background: #333;
margin-bottom: 20px;
border-radius: 50%;
cursor: pointer;
}
<body>
<main>
<div id="projects">
<div class="project">
<p>Some text example</p>
</div>
<div class="project">
<p>Some text example</p>
</div>
<div class="project">
<p>Some text example</p>
</div>
<div class="project">
<p>Some text example</p>
</div>
<div class="project">
<p>Some text example</p>
</div>
</div>
</main>
</body>
Solution 1:[1]
I hope I understood your question correctly. Is this what you're looking for?
const config = {
ease: 0.1,
current: 0,
previous: 0,
rounded: 0
}
class Scroll {
constructor(velocity) {
this.velocity = velocity
}
setBodyHeight() {
document.body.style.height = document.getElementById('projects').getBoundingClientRect().height + 'px'
}
isMobile() {
return 'ontouchstart' in document.documentElement && navigator.userAgent.match(/Mobi/)
}
onScroll() {
config.current = window.scrollY
config.previous += (config.current - config.previous) * config.ease
config.rounded = Math.round(config.previous * 100) / 100
const difference = config.current - config.rounded
const acceleration = difference / document.body.clientWidth
const velocity = +acceleration
const skew = velocity * this.velocity
const element = document.getElementById('projects')
this.isMobile() ? element.style.transform = `skewY(${skew}deg)` : element.style.transform = `translateY(-${config.rounded}px)`
requestAnimationFrame(() => this.onScroll())
}
}
class SideNavigation {
constructor() {
createBullets()
}
}
function createBullets() {
const bulletWrapper = document.createElement('div')
const bulletList = document.createElement('ul')
bulletWrapper.classList.add('side-nav')
for (let i = 0; i < document.getElementsByClassName('project').length; i++) {
const bullet = document.createElement('li')
bullet.setAttribute('id', '' + i)
bullet.addEventListener('click', event => {
console.log(document.getElementsByClassName('project')[parseInt(event.target.id)].offsetTop)
// scroll to current section
window.scrollBy(0, document.getElementsByClassName('project')[parseInt(event.target.id)].offsetTop - window.pageYOffset);
})
bulletList.append(bullet)
bulletWrapper.append(bulletList)
document.body.append(bulletWrapper)
}
}
window.addEventListener('load', () => {
const scrollInstance = new Scroll(8, true)
const sideNav = new SideNavigation()
scrollInstance.setBodyHeight()
requestAnimationFrame(() => scrollInstance.onScroll())
})
html,
body {
height: 100%;
}
main {
position: fixed;
left: 0;
top: 0;
height: 100%;
width: 100%;
overflow: hidden;
}
#projects {
width: 80%;
}
.project {
height: 500px;
width: 100%;
background: #333;
color: #fff;
}
.side-nav {
position: fixed;
right: 20px;
top: 20%;
z-index: 10;
}
.side-nav li {
width: 30px;
height: 30px;
display: block;
background: #333;
margin-bottom: 20px;
border-radius: 50%;
cursor: pointer;
}
<body>
<main>
<div id="projects">
<div class="project">
<p>Some text example</p>
</div>
<div class="project">
<p>Some text example</p>
</div>
<div class="project">
<p>Some text example</p>
</div>
<div class="project">
<p>Some text example</p>
</div>
<div class="project">
<p>Some text example</p>
</div>
</div>
</main>
</body>
The scrollBy function's second parameter allows to modify the window's Y axis. But as we want each bullet to jump to the start of it's project, we decrease the current Y axis of the page from the Y axis of the project window.scrollBy(0, document.getElementsByClassName('project')[parseInt(event.target.id)].offsetTop - window.pageYOffset).
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Rani Giterman |
