The Setup
<body class="example">
<main>
<section class="image">
<div class="image__bg" style="background-image: url('https://source.unsplash.com/9dD0gFvrFnY/1600x900');"></div>
</section>
<section class="image">
<div class="image__bg" style="background-image: url('https://source.unsplash.com/W5RuDkMkKzU/1600x900');"></div>
</section>
<section class="image">
<div class="image__bg" style="background-image: url('https://source.unsplash.com/MnxT92l-3Qo/1600x900');"></div>
</section>
<section class="image">
<div class="image__bg" style="background-image: url('https://source.unsplash.com/HKZPcz4Jpm8/1600x900');"></div>
</section>
<section class="image">
<div class="image__bg" style="background-image: url('https://source.unsplash.com/NMbKKrLTI_k/1600x900');"></div>
</section>
<section class="image">
<div class="image__bg" style="background-image: url('https://source.unsplash.com/Xcnq8hpUy9o/1600x900');"></div>
</section>
</main>
</body>
body {
background-color: #000;
}
.image {
position: relative;
height: 100vh;
width: 100%;
&__bg {
position: absolute;
top: 0;
left: 0;
z-index: 0;
height: 100%;
width: 100%;
background-position: 50%;
background-repeat: no-repeat;
background-size: cover;
overflow: hidden;
}
}
The Script
const OpacityScroll = (() => {
let s;
return {
settings() {
return {
windowHeight: window.innerHeight,
halfWindowHeight: window.innerHeight / 2,
windowWidth: window.innerWidth,
documentHeight: document.body.scrollHeight
};
},
init(page) {
s = this.settings();
this.bindEvents(page);
},
bindEvents(page) {
this.opacityScroll(page);
},
opacityScroll(page) {
const children = document.querySelectorAll(`.${page} main`)[0].children;
[].forEach.call(children, (child, idx) => {
child.style.left = 0;
if (idx === 0) {
child.style.position = 'fixed';
child.style.top = 0;
child.style.zIndex = 0;
} else {
child.style.position = 'absolute';
child.style.top = `${idx}00vh`;
child.style.zIndex = idx;
let scrollOffset = child.getBoundingClientRect().top + document.body.scrollTop;
let opacityTrigger = s.windowHeight * idx - s.halfWindowHeight;
window.addEventListener('resize', () => {
scrollOffset = child.getBoundingClientRect().top + document.body.scrollTop;
s.windowHeight = window.innerHeight;
s.halfWindowHeight = s.windowHeight / 2;
s.documentHeight = document.body.scrollHeight;
opacityTrigger = s.windowHeight * idx - s.halfWindowHeight;
});
window.addEventListener('scroll', opacityChange);
window.addEventListener('resize', opacityChange);
function opacityChange() {
const scrollTop = document.documentElement.scrollTop;
const prev = child.previousElementSibling;
const opacity = 1 - (scrollTop - opacityTrigger) / scrollTop * idx * 2;
if (scrollTop >= opacityTrigger) {
prev.style.opacity = opacity > 0 ? opacity : 0;
} else {
prev.style.opacity = 1;
}
if (scrollTop >= scrollOffset && scrollTop + s.windowHeight !== s.documentHeight) {
child.style.position = 'fixed';
child.style.top = 0;
} else {
child.style.position = 'absolute';
child.style.top = `${idx}00vh`;
child.style.left = 0;
child.style.zIndex = idx;
}
}
}
});
}
};
})();
OpacityScroll.init('example');