Parallax and Loop
by jacob_truax
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<link rel="stylesheet" href="normalize.css">
<link rel="stylesheet" href="style.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.0.2/TweenMax.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.1.2/TimelineMax.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.0/jquery.min.js"></script>
</head>
<body>
<main>
<div class="Loop js-loop">
<section>
<div class="info">
<h2>Hello 1</h2>
<p>Hello 1</p>
</div>
</section>
<section>
<div class="info">
<h2>Hello 2</h2>
<p>Hello 2</p>
</div>
</section>
<section>
<div class="info">
<h2>Hello 3</h2>
<p>Hello 3</p>
</div>
</section>
<section>
<div class="info">
<h2>Hello 4</h2>
<p>Hello 4</p>
</div>
</section>
<section>
<div class="info">
<h2>Hello 5</h2>
<p>Hello 5</p>
</div>
</section>
<section>
<div class="info">
<h2>Hello 6</h2>
<p>Hello 6</p>
</div>
</section>
<section>
<div class="info">
<h2>Hello 7</h2>
<p>Hello 7</p>
</div>
</section>
<section>
<div class="info">
<h2>Hello 8</h2>
<p>Hello 8</p>
</div>
</section>
<!--
These blocks are the same as the first blocks to get that looping illusion going.
You need to add clones to fill out a full viewport height.
-->
<section class="is-clone">
<div class="info">
<h2>Hello 1</h2>
<p>Hello 1</p>
</div>
</section>
<section class="is-clone">
<div class="info">
<h2>Hello 2</h2>
<p>Hello 2</p>
</div>
</section>
</div>
</main>
</body>
CSS
html,
body {
height: 100%;
/* overflow: hidden; */
}
body {
color: #000;
}
main {
height: 100%;
position: relative;
top: 0;
left: 0;
}
header {
position: fixed;
top: 0;
left: 0;
width: 100%;
text-align: center;
z-index: 1;
}
.Loop {
position: absolute;
height: 100%;
overflow: auto;
}
section {
position: relative;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
width: 100vw;
height: 100vh;
}
::scrollbar {
display: none;
}
section div {
position: absolute;
z-index: 2;
text-align: center;
width: 50%;
background-color: #ff0000;
}
section img {
position: relative;
width: 50%;
background-color: #000;
}
JavaScript
const sections = document.querySelectorAll("section")
const divTag = document.querySelector("div.Loop")
const mainTag = document.querySelector("main")
var doc = window.document,
clones = divTag.querySelectorAll('.is-clone'),
disableScroll = false,
scrollHeight = 0,
scrollPos = 0,
clonesHeight = 0,
i = 0;
const addMovement = function() {
const topViewport = divTag.scrollTop
const midViewport = topViewport + (divTag.offsetHeight / 2)
sections.forEach(section => {
const topSection = section.offsetTop
const midSection = topSection + (section.offsetHeight / 2)
const distanceToSection = (midViewport - midSection)
console.log(distanceToSection)
const image = section.querySelector(".info")
image.style.transform = `rotate(${distanceToSection}deg)`
})
}
addMovement()
function getScrollPos () {
return (divTag.offsetTop || divTag.scrollTop) - (divTag.clientTop || 0);
}
function setScrollPos (pos) {
divTag.scrollTop = pos;
}
function getClonesHeight () {
clonesHeight = 0;
for (i = 0; i < clones.length; i += 1) {
clonesHeight = clonesHeight + clones[i].offsetHeight;
}
return clonesHeight;
}
function reCalc () {
scrollPos = getScrollPos();
scrollHeight = divTag.scrollHeight;
clonesHeight = getClonesHeight();
if (scrollPos <= 0) {
setScrollPos(1); // Scroll 1 pixel to allow upwards scrolling
}
}
function scrollUpdate () {
if (!disableScroll) {
scrollPos = getScrollPos();
if (clonesHeight + scrollPos >= scrollHeight) {
// Scroll to the top when you’ve reached the bottom
setScrollPos(1); // Scroll down 1 pixel to allow upwards scrolling
disableScroll = true;
} else if (scrollPos <= 0) {
// Scroll to the bottom when you reach the top
setScrollPos(scrollHeight - clonesHeight);
disableScroll = true;
}
}
if (disableScroll) {
// Disable scroll-jumping for a short time to avoid flickering
window.setTimeout(function () {
...