
A fullscreen one page scrolling effect that enables users to scroll through fullpage sections with the mouse wheel.
Also comes with a side progress bar that auto-updates based on the current scroll position.
How to use it:
1. The required HTML structure.
<div class="layout">
<div class="section-stick">
<div class="stick active"></div>
</div>
<section class="s1">
<div class="home">
<span>Slider Scroll Example</span>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" focusable="false" width="1em" height="1em" style="-ms-transform: rotate(360deg); -webkit-transform: rotate(360deg); transform: rotate(360deg);" preserveAspectRatio="xMidYMid meet" viewBox="0 0 20 20"><path d="M5 6l5 5l5-5l2 1l-7 7l-7-7z" fill="#fff"/><rect x="0" y="0" width="20" height="20" fill="rgba(0, 0, 0, 0)" /></svg>
</div>
</section>
<section class="s2">Section Two</section>
<section class="s3">Section Three</section>
<section class="s4">Section Four</section>
</div>2. The required CSS styles.
:root {
--color-white: #fff;
--time-animation: 0.6s;
}
@keyframes pulse {
0% {
transform: translateY(0px);
}
50% {
transform: translateY(25px);
}
100% {
transform: translateY(0px);
}
}
html {
scrollbar-width: none;
}
body {
margin: 0;
padding: 0;
font-family: sans-serif;
overflow: hidden scroll;
-ms-overflow-style: none;
}
body::-webkit-scrollbar {
display: none;
}
.layout {
width: 100%;
height: calc(100vh * 3);
position: relative;
}
.layout .section-stick {
margin: auto;
position: fixed;
right: 50px;
bottom: 50px;
display: flex;
flex-direction: column;
row-gap: 30px;
align-items: center;
justify-content: flex-start;
z-index: 1000;
}
.layout .section-stick .stick,
.layout .section-stick .active {
width: 13px;
height: 62px;
border: none;
border-radius: 9px;
}
.layout .section-stick .stick {
position: relative;
background-color: rgba(255, 255, 255, 0.4);
transition: all var(--time-animation) ease-in-out;
}
.layout .section-stick .active {
position: absolute;
background-color: var(--color-white);
box-shadow: 0px 0px 12px 1px var(--color-white);
backdrop-filter: blur(3px);
-webkit-backdrop-filter: blur(3px);
}
.layout section {
width: 100%;
height: 100vh;
position: fixed;
top: 0;
left: 0;
right: 0;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
color: var(--color-white);
font-size: 80px;
font-weight: 600;
transform: translateY(100vh);
transition: all var(--time-animation) ease-in-out;
z-index: 0;
}
.layout section .home {
display: flex;
flex-direction: column;
row-gap: 45px;
align-items: center;
}
.layout section .home svg {
animation: pulse 1.4s linear infinite normal;
}
.layout .s1 {
background-color: #4d2536;
transform: translateY(0);
z-index: 4;
}
.layout .s2 {
background-color: #02486b;
z-index: 3;
}
.layout .s3 {
background-color: #171716;
z-index: 2;
}
.layout .s4 {
background-color: #154621;
z-index: 1;
}
/*** RESPONSIVE ***/
/* MOBILE */
@media screen and (max-width: 576px) {
body::-webkit-scrollbar {
width: 0px;
background: transparent;
-webkit-appearance: none;
}
.layout .section-stick {
right: 20px;
bottom: 20px;
transform: scale(0.7);
}
.layout section {
font-size: 40px;
}
}
3. The main JavaScript to enable the one page scrolling effect.
const TIME_OUT = 600 // It should be the same transition time of the sections
const body = document.querySelector('body')
const sectionsQty = document.querySelectorAll('section').length
const sectionStick = document.querySelector('.section-stick')
let startFlag = true
let initialScroll = window.scrollY
let qty = 1,
main = null,
next = null
// Add child elements in .section-stick as number of sections exist
Array(sectionsQty)
.fill()
.forEach(() => {
sectionStick.innerHTML = sectionStick.innerHTML + '<div class="stick"></div>'
})
console.log('SLIDE', qty)
// Listening to scroll event
window.onscroll = () => {
if (startFlag) {
const scrollDown = this.scrollY >= initialScroll
const scrollLimit = qty >= 1 && qty <= sectionsQty
// Verify that the scroll does not exceed the number of sections
if (scrollLimit) {
body.style.overflowY = 'hidden' // Lock el scroll
if (scrollDown && qty < sectionsQty) {
main = document.querySelector(`section.s${qty}`)
next = document.querySelector(`section.s${qty + 1}`)
main.style.transform = 'translateY(-100vh)'
next.style.transform = 'translateY(0)'
qty++
} else if (!scrollDown && qty > 1) {
main = document.querySelector(`section.s${qty - 1}`)
next = document.querySelector(`section.s${qty}`)
main.style.transform = 'translateY(0)'
next.style.transform = 'translateY(100vh)'
qty--
}
// Scroll progressbar
const active = document.querySelector('.section-stick .stick.active')
active.style.top = (62 + 30) * (qty - 1) + 'px'
}
console.log('SLIDE', qty)
// Wait for the scrolling to finish to reset the values
setTimeout(() => {
initialScroll = this.scrollY
startFlag = true
body.style.overflowY = 'scroll' // Unlock scroll
}, TIME_OUT)
startFlag = false
}
// Keep scrollbar in the middle of the viewport
window.scroll(0, window.screen.height)
}






