The Context
I'm building an infinite horizontal scroll of images:
<div class="infinite-thumbs">
<img src="1.jpg" class="thumb thumb-one">
<img src="2.jpg" class="thumb thumb-two">
<img src="3.jpg" class="thumb thumb-three">
...
<img src="10.jpg" class="thumb thumb-ten">
</div>
<style lang="stylus">
.infinite-thumbs
position absolute
width 100%
height 180px
bottom 40px
white-space nowrap
overflow auto
overflow-y hidden
.thumb
position relative
display inline-block
width 200px
height 180px
</style>
Learn more about Stylus here: stylus-lang.com
And then I've got some jQuery/JS
to handle the cloning and appending of images when they're off-screen:
function scrollUpdate() {
$('.thumb').each(function() {
var bounding = $(this)[0].getBoundingClientRect();
if (bounding.right < 0) {
var $el = $(this);
$el.clone(true).appendTo('.infinite-thumbs');
$el.remove();
}
});
}
$('.infinite-thumbs').on('scroll', function () {
window.requestAnimationFrame(scrollUpdate);
});
So scrollUpdate()
loops over each of the .thumb
elements and checks to see if it's visible on-screen. If it's not (bounding.right < 0
) then it gets cloned and appended to the end of the .infinite-thumbs
element.
The Problem
The problem I have is that once one of the .thumb
elements returns a negative value for bounding.right
all the .thumb
elements return the exact same set of bounding
values.
So when all are visible, I get this in my console:
.thumb-one: { top : 0, right : 200, ... }
.thumb-two: { top : 0, right : 400, ... }
.thumb-three: { top : 0, right : 600, ... }
...
.thumb-ten: { top : 0, right : 2000, ... }
But as soon as the first child element (.thumb-one
) obtains a negative bounding.right
value, I get this in my console:
.thumb-one: { top : 0, right : -1, ... }
.thumb-two: { top : 0, right : -1, ... }
.thumb-three: { top : 0, right : -1, ... }
...
.thumb-ten: { top : 0, right : -1, ... }
What gives? Why would they all return a bounding
object with the exact same values just because one of them is off-screen?
Anyone have any idea what's going on here?
NOTE:
Both
$.fn.offset()
and$.fn.position()
behave in the same way asgetBoundingClientRect()
; they return the same set of values for each.thumb
once.thumb-one
has a negative value in its result.
It happens because you remove the element before check all the thumbs' positions. Removing the first element causes that the next element becomes the first, going off-screen. This way, every thumb will assume the same 'right' position.
The solution Create a temporary array outside the 'each' cycle and use it to save the off-screen thumbs. Then, after the cycle, clone, remove and append elements in the same way as before. Something like this:
function scrollUpdate() {
var offScreenElements = [];
$('.thumb').each(function() {
var bounding = $(this)[0].getBoundingClientRect();
if (bounding.right < 0) {
offScreenElements.push($(this));
}
});
$.each(offScreenElements, function(index, element) {
element.clone(true).appendTo('.infinite-thumbs');
element.remove();
});
}