Skip to content

Instantly share code, notes, and snippets.

@deepakgudi-pixel
Created April 20, 2022 17:20
Show Gist options
  • Save deepakgudi-pixel/9dadbd4d2580c16c0c8585b3bcdf1e40 to your computer and use it in GitHub Desktop.
Save deepakgudi-pixel/9dadbd4d2580c16c0c8585b3bcdf1e40 to your computer and use it in GitHub Desktop.
smooth scrolling effect for websites
const mainTag = document.querySelector("main")
const bodyTag = document.querySelector("body")
const cursorTag = document.querySelector("div.cursor")
const cursorInnerTag = document.querySelector("div.cursor-inner")
const captions = document.querySelectorAll("figcaption")
const motion = window.matchMedia('(prefers-reduced-motion: no-preference)')
const large = window.matchMedia('(min-width: 600px)')
const observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.intersectionRatio > 0.5) {
entry.target.classList.add("in-view")
}
})
}, {
threshold: [0, 0.1, 0.5, 1]
})
if (motion.matches && large.matches) {
// styling with JS so we can scroll with JS turned off
mainTag.style.position = "fixed"
mainTag.style.top = 0
mainTag.style.left = 0
mainTag.style.width = "100%"
// where are we, vs where we wanna be
let currentScroll = 0
let aimScroll = 0
let currentCursorX = 0
let currentCursorInnerX = 0
let aimCursorX = 0
let currentCursorY = 0
let currentCursorInnerY = 0
let aimCursorY = 0
captions.forEach(caption => {
observer.observe(caption)
})
// make a bit of code that'll run every frame
const changeScroll = function () {
// we need to make the whole page the same height as this too so we can scroll down to the same distance
bodyTag.style.height = mainTag.offsetHeight + "px"
// is there any diff between aim and current?
// if so, tween towards the aim
// 0.05 is how quickly/slowly to aim
currentScroll += (aimScroll - currentScroll) * 0.1
// then move the whole 'page', actually, the main tag, for this current scroll position
// minus we we're moving the main Tag up as we scroll down
// mainTag.style.top = (-1 * currentScroll) + "px"
mainTag.style.transform = `translate(0, ${-1 * currentScroll}px)`
document.querySelectorAll("figcaption").forEach(caption => {
const box = caption.getBoundingClientRect()
const midY = box.y + box.height / 2
const midScreen = window.innerHeight / 2
const diff = midY - midScreen
const images = caption.querySelectorAll("img")
images.forEach((image, index) => {
const speed = 0.05 * index
image.style.transform = `translate(0, ${diff * speed}px)`
})
})
// run this every 'frame'
requestAnimationFrame(changeScroll)
}
const changeCursor = function () {
currentCursorX += (aimCursorX - currentCursorX) * 0.1
currentCursorY += (aimCursorY - currentCursorY) * 0.1
currentCursorInnerX += (aimCursorX - currentCursorInnerX) * 0.15
currentCursorInnerY += (aimCursorY - currentCursorInnerY) * 0.15
cursorTag.style.left = currentCursorX + "px"
cursorTag.style.top = currentCursorY + "px"
cursorInnerTag.style.left = currentCursorInnerX + "px"
cursorInnerTag.style.top = currentCursorInnerY + "px"
requestAnimationFrame(changeCursor)
}
// when we scroll, update the aim
window.addEventListener("scroll", function () {
aimScroll = window.pageYOffset
})
document.addEventListener("mousemove", function (event) {
aimCursorX = event.pageX
aimCursorY = event.pageY
})
const links = document.querySelectorAll("a")
links.forEach(link => {
link.addEventListener("mouseenter", function () {
bodyTag.classList.add("hovering")
})
link.addEventListener("mouseleave", function () {
bodyTag.classList.remove("hovering")
})
})
changeScroll()
changeCursor()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment