I am trying to implement a slip-scroll parallax type effect using CSS and JavaScript. When the screen scrolls down, the logo in the top right will change it's background to contrast with what is below. There is also a nav button on the left that does the same.
I have this so far...
// Detect request animation frame
var scroll = window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.msRequestAnimationFrame ||
window.oRequestAnimationFrame
// IE Fallback, you can even fallback to onscroll
||
function(callback) {
window.setTimeout(callback, 1000 / 60)
};
var lastPosition = -1;
// my Variables
var lastSection = false;
var replaceItemTop = -1;
var replaceItemBottom = -1;
var replaceItemHeight = -1;
// The Scroll Function
function loop() {
var top = window.pageYOffset;
// my variables
// my sections to calculate stuff
var sections = document.querySelectorAll('.section');
var replaceContainer = document.querySelectorAll('.js-replace');
var replaceItem = document.querySelectorAll('.js-replace__item');
if (replaceItem.length > 0) {
// get top position of item from container, because image might not have loaded
replaceItemTop = parseInt(replaceContainer[0].getBoundingClientRect().top);
replaceItemHeight = replaceItem[0].offsetHeight;
replaceItemBottom = replaceItemTop + replaceItemHeight;
}
var sectionTop = -1;
var sectionBottom = -1;
var currentSection = -1;
// Fire when needed
if (lastPosition == window.pageYOffset) {
scroll(loop);
return false;
} else {
lastPosition = window.pageYOffset;
// Your Function
Array.prototype.forEach.call(sections, function(el, i) {
sectionTop = parseInt(el.getBoundingClientRect().top);
sectionBottom = parseInt(el.getBoundingClientRect().bottom);
// active section
if ((sectionTop <= replaceItemBottom) && (sectionBottom > replaceItemTop)) {
// check if current section has bg
currentSection = el.classList.contains('section--bg');
// switch class depending on background image
if (currentSection) {
replaceContainer[0].classList.remove('js-replace--reverse');
} else {
replaceContainer[0].classList.add('js-replace--reverse')
}
}
// end active section
// if active Section hits replace area
if ((replaceItemTop < sectionTop) && (sectionTop <= replaceItemBottom)) {
// animate only, if section background changed
if (currentSection != lastSection) {
document.documentElement.style.setProperty('--replace-offset', 100 / replaceItemHeight * parseInt(sectionTop - replaceItemTop) + '%');
}
}
// end active section in replace area
// if section above replace area
if (replaceItemTop >= sectionTop) {
// set offset to 0 if you scroll too fast
document.documentElement.style.setProperty('--replace-offset', 0 + '%');
// set last section to current section
lastSection = currentSection;
}
});
}
// Recall the loop
scroll(loop)
}
// Call the loop for the first time
loop();
window.onresize = function(event) {
loop();
};
/* variables */
:root {
/* this value is going to be changed by javascript */
--replace-offset: 50%;
--replace-offset-2: calc((100% - var(--replace-offset)) * -1)
}
a {
text-decoration: none;
}
/* set image position */
img {
vertical-align: bottom;
}
.footer {
background-color: black;
color: white;
padding-top: 50px;
padding-bottom: 50px;
text-align: center;
}
/* without fixed header this makes no sense */
.header {
position: fixed;
top: 0;
right: 0;
z-index: 9;
}
.header_nav {
position: fixed;
top: 50%;
transform: translateY(-50%);
left: 0;
z-index: 9;
}
.logo {
background-color: white;
display: inline-block;
border: solid;
padding: 10px;
border-radius: 10px;
font-size: 2em;
}
.logo a {
color: black;
}
.logo--invert {
background-color: black;
color: white;
border-color: white;
}
.logo--invert a {
color: white;
}
.sidelogo {
background-color: white;
display: inline-block;
border: solid;
padding: 10px;
border-radius: 10px;
font-size: 2em;
}
.sidelogo a {
color: black;
}
.sidelogo--invert {
background-color: black;
color: white;
border-color: white;
}
.sidelogo--invert a {
color: white;
}
.section {
min-height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
text-align: center;
}
section--1 {
height: 100vh;
width: 100%;
}
.hero {
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
background-image: linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), url("https://www.w3schools.com/howto/photographer.jpg");
background-position: center;
background-repeat: no-repeat;
background-size: cover;
}
.section--2 {
background: white;
}
.section--3 {
background: black;
color: white;
}
/**
This is the interesting part
**/
/* align content above each other without absolute */
.js-replace {
display: grid;
}
.js-replace__item {
grid-row: -1 / 1;
grid-column: -1 / 1;
overflow: hidden;
will-change: transform;
}
/* item to replace with */
.js-replace__item {
transform: translateY(calc(var(--replace-offset) * 1));
}
.js-replace__content {
/* fixes problem with calculating correct height in js */
border: 1px solid transparent;
will-change: transform;
transform: translateY(calc(var(--replace-offset) * -1));
}
/* previous replace item*/
.js-replace__item--active {
transform: translateY(calc(var(--replace-offset-2) * 1));
}
.js-replace__item--active .js-replace__content {
transform: translateY(calc(var(--replace-offset-2) * -1));
}
/* REVERSE ANIMATION */
.js-replace--reverse .js-replace__item {
transform: translateY(calc(var(--replace-offset-2) * 1));
}
.js-replace--reverse .js-replace__content {
transform: translateY(calc(var(--replace-offset-2) * -1));
}
/* previous replace item*/
.js-replace--reverse .js-replace__item--active {
transform: translateY(calc(var(--replace-offset) * 1));
}
.js-replace--reverse .js-replace__item--active .js-replace__content {
transform: translateY(calc(var(--replace-offset) * -1));
}
<body class="body">
<div class="header">
<!-- replace content -->
<div class="header__logo js-replace">
<!-- item to replace -->
<div class="js-replace__item js-replace__item--active">
<div class="js-replace__content">
<div class="logo"><a href="#">Logo</a></div>
</div>
</div>
<!-- end item to replace -->
<!-- item to replace with -->
<div class="js-replace__item">
<div class="js-replace__content">
<div class="logo logo--invert"><a href="#">Logo</a></div>
</div>
</div>
<!-- end item to replace with -->
</div>
<!-- end replace content -->
</div>
<div class="header_nav">
<!-- replace content -->
<div class="header__side js-replace">
<!-- item to replace -->
<div class="js-replace__item js-replace__item--active">
<div class="js-replace__content">
<div class="sidelogo"><a href="#">Nav</a></div>
</div>
</div>
<!-- end item to replace -->
<!-- item to replace with -->
<div class="js-replace__item">
<div class="js-replace__content">
<div class="sidelogo sidelogo--invert"><a href="#">Nav</a></div>
</div>
</div>
<!-- end item to replace with -->
</div>
<!-- end replace content -->
</div>
<main class="main">
<section class="section--1 section">
<div class="hero">
</div>
</section>
<section class="section--2 section section--bg">
<h1>Section 2</h1>
<p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est.
Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, commodo vitae, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis
tempus lacus enim ac dui. Donec non enim in turpis pulvinar facilisis. Ut felis. Praesent dapibus, neque id cursus faucibus, tortor neque egestas augue, eu vulputate magna eros eu erat. Aliquam erat volutpat. Nam dui mi, tincidunt quis, accumsan
porttitor, facilisis luctus, metus</p>
<p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est.
Mauris placerat eleifend leo.</p>
</section>
<section class="section--3 section">
<h1>Section 3</h1>
<p>
<strong>Pellentesque habitant morbi tristique</strong> senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. <em>Aenean ultricies mi vitae est.</em> Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, <code>commodo vitae</code>, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci,
sagittis tempus lacus enim ac dui. <a href="#">Donec non enim</a> in turpis pulvinar facilisis. Ut felis.
</p>
<h2>Header Level 2</h2>
<ol>
<li>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</li>
<li>Aliquam tincidunt mauris eu risus.</li>
</ol>
<blockquote>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus magna. Cras in mi at felis aliquet congue. Ut a est eget ligula molestie gravida. Curabitur massa. Donec eleifend, libero at sagittis mollis, tellus est malesuada tellus, at luctus
turpis elit sit amet quam. Vivamus pretium ornare est.</p>
</blockquote>
<h3>Header Level 3</h3>
<ul>
<li>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</li>
<li>Aliquam tincidunt mauris eu risus.</li>
</ul>
</section>
<section class="section--4 section section--bg">
<h1>Section 4</h1>
<p>
Some great section 4 content
</p>
<ul>
<li>This is a list item</li>
<li>This is a list item</li>
<li>This is a list item</li>
<li>This is a list item</li>
<li>This is a list item</li>
</ul>
</section>
<section class="section--5 section section--bg">
<h1 class="section__title">
Section 5
</h1>
<p>
This is some random content for section 5
</p>
</section>
</main>
<footer class="footer section">
<form action="#" method="post">
<div>
<label for="name">Text Input:</label>
<input type="text" name="name" id="name" value="" tabindex="1" />
</div>
<div>
<h4>Radio Button Choice</h4>
<label for="radio-choice-1">Choice 1</label>
<input type="radio" name="radio-choice-1" id="radio-choice-1" tabindex="2" value="choice-1" />
<label for="radio-choice-2">Choice 2</label>
<input type="radio" name="radio-choice-2" id="radio-choice-2" tabindex="3" value="choice-2" />
</div>
<div>
<label for="select-choice">Select Dropdown Choice:</label>
<select name="select-choice" id="select-choice">
<option value="Choice 1">Choice 1</option>
<option value="Choice 2">Choice 2</option>
<option value="Choice 3">Choice 3</option>
</select>
</div>
<div>
<label for="textarea">Textarea:</label>
<textarea cols="40" rows="8" name="textarea" id="textarea"></textarea>
</div>
<div>
<label for="checkbox">Checkbox:</label>
<input type="checkbox" name="checkbox" id="checkbox" />
</div>
<div>
<input type="submit" value="Submit" />
</div>
</form>
</footer>
</body>
The Logo on the right is behaving as expected, the background changes as you scroll down the page.
However, the nav on the left is not working correctly, I think it needs some offset adding as currently it changes when the nav changes
Anyone any ideas where I am going wrong?