I have got a multi-layered parallax script currently semi-working. If lets say the elements with the parallax effect is placed at the top of the website then the effect works spot on, as it scrolled out of view you can't see the layers moving out of frame.
However I want to be able to use this script on multiple elements throughout the page, at different positions. See the example below, you can see the effect works alright, but if you add some margin to the data-parallax="panel-1"
section you will see there is now an issue.
/**
* @author Martyn Lee Ball
* @desc Creates multi-layer Parallax effect
* @version 1.0
* @return {Array} Returns instances of classes as Array
*/
class Parallax {
constructor(node) {
const self = this;
// Settings and defaults
self.settings = {
container: node,
height: node.clientHeight,
name: node.dataset.parallax,
layers: [],
defaultDepth: 0.5,
offset: function(element) {
let top = 0;
do {
top += element.offsetTop || 0;
element = element.offsetParent;
} while(element);
return {
top: self.normalizeInt(top)
};
}.call(self, node)
};
// Populate layers setting with objects
(function() {
let layers = (self.settings.container).querySelectorAll('[data-layer]');
let count = 0;
for (const layer in layers) {
if (layers.hasOwnProperty(layer)) {
self.settings.layers.push({
// Set the depth to the default if not defined
depth: (function() {
if (layers[layer].dataset.depth !== undefined)
return parseFloat(layers[layer].dataset.depth);
return self.settings.defaultDepth;
}.call(self)),
// Keep reference to the element
element: layers[layer],
// Get the layer name, not essential
name: layers[layer].dataset[layer]
});
// Fix layer heights
}
count++;
}
}.call(this));
this.setupScrollEvent.call(this);
}
normalizeInt(num) {
return Math.round(num * 10) / 10;
}
setupScrollEvent() {
const self = this;
window.addEventListener('scroll', function() {
self.last_known_scroll_position = window.scrollY || document.documentElement.scrollTop;
if (!self.ticking) {
window.requestAnimationFrame(function() {
self.scrolledEvent.call(self, self.last_known_scroll_position);
self.ticking = false;
});
self.ticking = true;
}
});
self.last_known_scroll_position = window.scrollY || document.documentElement.scrollTop;
self.scrolledEvent.call(self, self.last_known_scroll_position);
}
scrolledEvent(scrollY) {
const self = this;
if ((window.outerHeight + scrollY) < self.settings.offset.top) return;
for (const layer in self.settings.layers) {
if ((self.settings.layers).hasOwnProperty(layer)) {
let movement = -self.normalizeInt((((scrollY * self.settings.layers[layer].depth) - scrollY)));
let translate3d = 'translate3d(0, ' + movement + 'px, 0)';
self.settings.layers[layer].element.style['-webkit-transform'] = translate3d;
self.settings.layers[layer].element.style['-moz-transform'] = translate3d;
self.settings.layers[layer].element.style['-ms-transform'] = translate3d;
self.settings.layers[layer].element.style['-o-transform'] = translate3d;
self.settings.layers[layer].element.style.transform = translate3d;
}
}
}
static initialize() {
// Ensure DOM has loaded
window.addEventListener('load', function() {
let instances = [];
// Does page contain any parallax panels?
let panels = document.querySelectorAll('[data-parallax]');
if (panels.length > 0) {
// Parallax panels found, create instances of class and return them for reference
for (const panel in panels) {
if (panels.hasOwnProperty(panel)) {
instances.push(new this(panels[panel]));
}
}
}
if (panels.length > 0) {
window.parallaxInstance = instances;
}
}.bind(this));
}
}
Parallax.initialize();
html,
body {
margin: 0;
padding: 0;
}
section[data-parallax] {
height: 400px;
position: relative;
overflow: hidden;
border: 1px solid black;
border-width: 1px 0 1px 0;
}
section[data-parallax] > div {
position: absolute;
z-index: -1;
background-position: bottom center;
background-size: auto;
background-repeat: no-repeat;
width: 100%;
height: 100%;
}
section[data-parallax] > div[data-layer='layer-bg'] {
background-image: url('https://i.imgur.com/F7pqpWZ.jpg');
}
section[data-parallax] > div[data-layer='layer-1'] {
background-image: url('https://i.imgur.com/uxpVhe1.png');
background-position: left bottom;
}
section[data-parallax] > div[data-layer='layer-2'] {
background-image: url('https://i.imgur.com/JeGChIm.png');
}
section[data-parallax] > div[data-layer='layer-3'] {
background-image: url('https://i.imgur.com/V7l8cxD.png');
background-position: right bottom;
}
section[data-parallax] > div[data-layer='layer-4'] {
background-image: url('https://i.imgur.com/joB5tI4.png');
}
section[data-parallax] > div[data-layer='layer-overlay'] {
background-image: url('https://i.imgur.com/h1ybMNZ.png');
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Parallax Development</title>
<script src="parallax-dev.js" type="text/javascript"></script>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<section data-parallax="panel-1">
<div data-layer="layer-bg" data-depth="0.10"></div>
<div data-layer="layer-1" data-depth="0.20"></div>
<div data-layer="layer-2" data-depth="0.50"></div>
<div data-layer="layer-3" data-depth="0.80"></div>
<div data-layer="layer-4" data-depth="1.0"></div>
</section>
<section style="padding-bottom: 200vh;"></section>
</body>
</html>
Mainly my issue is when I attempt to move the parallaxed element from the top of the page, as now the top of the layers which are moving slower can be seen.
I believe what I need to do is to resize these layers based on their depth, so for example the layer with the depth value of 0.10
is really slow.
So I need to make the layers appear as seen in the below illustration to the right, as currently they are positioned as they appear on the left?
I keep coming back to this and been trying to get it working for weeks now, on and off. I really can't get my head around what I need to do to solve this, I believe it's some simple mathematics to workout how much bigger the layers need to be in order to now show the edges as the user scrolls.
I will try to answer even if I am not sure I've got the question well)
Regarding depth: your code has already depth functionality, so you only have to read depth from data-depth attr, like that:
defaultDepth: node.dataset.depth
And your pictures has same height, so for these particular pictures you don't have to apply any padding top or some other offset from the top like on right picture. Applying depth is enough unless you have some other pictures.
And here what i have after depth applying: http://plnkr.co/edit/bNPzXFg83UtGF9PFWCQc?p=preview
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With