I have an arrangement of elements on the page – positions controlled via a CMS which gives each element a width, top position, left position, z-index and 'speed'.
The speed is used to create a parallax effect using JS. It takes it's 'speed' and calculates this by the window.pageYOffset
– if the speed is less than 0 then it divides the window.pageYOffset
by the speed and if it's more than 0 then it multiplies the window.pageYOffset
by the speed. On scroll it then adjusts the Y translation to give this 'parallax' effect.
This is generally all fine but of course as you alter the Y positions of the elements on scroll you are left with a 'gap' at the bottom (where the elements would be if the scroll speed matched the user scroll speed).
To rectify this I thought I would get the most bottom element, and get it's getBoundingClientRect().bottom
position and on scroll reduce the height of the container to match the bottom of this element so as you scroll down or up the container would contract/expand to match and thus removing the gap.
However, this doesn't seem to work. The math/logic is either wrong or I'm missing the entire thing.
Below is my code and I have set up a JSFiddle to help visualise this.
https://jsfiddle.net/6up3vqjn/2/
// Runs on init and resize
function parallaxInit() {
var $container = $('.parallax'),
container = $container[0];
var testArray = [],
$testLastElement;
$('.parallax > .group').each(function() {
var $group = $(this),
group = $group[0],
groupBounds = group.getBoundingClientRect(),
$lastElement,
lastElementBoundsBottom = 0;
$group.find('> div').each(function() {
var $div = $(this),
div = $div[0],
initTop = $div.attr('data-top');
if (initTop == 0) {
$div.css('top', '0');
} else {
$div.css('top', $(window).width() / 12 * initTop - 26 + 'px');
};
group.removeAttribute('style');
$group.height(group.scrollHeight).attr('data-height', group.scrollHeight);
var divBounds = div.getBoundingClientRect();
testArray.push(divBounds.bottom);
});
});
$('.parallax > .group > div').each(function() {
var divBottomBounds = $(this)[0].getBoundingClientRect().bottom;
if (divBottomBounds == Math.max.apply(Math, testArray)) {
$testLastElement = $(this);
$(this).addClass('is--last');
}
var letters = "0123456789ABCDEF";
var color = '#';
for (var i = 0; i < 6; i++) color += letters[(Math.floor(Math.random() * 16))];
$(this).css('background-color', color);
});
$container[0].style.height = $testLastElement[0].getBoundingClientRect().bottom + 'px';
}
parallaxInit();
$(window).on('resize', parallaxInit);
// Runs on scroll
function parallax() {
var $container = $('.parallax');
var test = 0;
var testArray = [],
$testLastElement;
$('.parallax > .group').each(function() {
var $group = $(this),
group = $group[0],
groupHeight = $group.attr('data-height'),
groupBounds = group.getBoundingClientRect();
$group.find('> div').each(function() {
var $this = $(this),
speed = $this.attr('data-speed');
if (speed < 0) {
speed = Math.abs(speed);
var yPos = window.pageYOffset / speed;
} else {
var yPos = window.pageYOffset * speed;
}
yPos = -yPos;
$this[0].style.transform = "translate3d(0, " + yPos + "px, 0)";
var divBounds = $this[0].getBoundingClientRect(),
divRelativeBounds = {};
testArray.push(divBounds.bottom);
});
});
$('.parallax > .group > div').each(function() {
var divBottomBounds = $(this)[0].getBoundingClientRect().bottom;
$(this).removeClass('is--last');
if (divBottomBounds == Math.max.apply(Math, testArray)) {
$testLastElement = $(this);
$(this).addClass('is--last');
}
});
$container[0].style.height = $testLastElement[0].getBoundingClientRect().bottom + 'px';
}
$(window).bind('scroll', parallax);
UPDATED JSFiddle with container height calculation removed: https://jsfiddle.net/ejqhvz2c/