I've got a side scrolling / horizontal layout site I'm building. I use a function to test whether or not an element is in the viewport on "normal" vertical layout sites in order to add classes, animations, etc. once it es into view.
I'm trying to get the same effect for the horizontal layout, but to no avail.
Here is the regular version of the function -
$.fn.isInViewport = function() {
if ( $(this).length ) {
var elementTop = $(this).offset().top;
}
var elementBottom = elementTop + $(this).outerHeight();
var viewportTop = $(window).scrollTop();
var viewportBottom = viewportTop + $(window).height();
return elementBottom > viewportTop && elementTop < viewportBottom;
};
And here is the way I tried it for horizontal layouts, which didn't work.
$.fn.isInViewport = function() {
if ( $(this).length ) {
var elementLeft = $(this).offset().left;
}
var elementRight = elementLeft + $(this).outerWidth();
var viewportLeft = $(window).scrollLeft();
var viewportRight = viewportLeft + $(window).width();
return elementRight > viewportLeft && elementLeft < viewportRight;
};
You call the function like so
$(".element").each(function() {
if ( $(this).isInViewport() ) {
$(this).addClass("animate-element");
}
});
I've got a side scrolling / horizontal layout site I'm building. I use a function to test whether or not an element is in the viewport on "normal" vertical layout sites in order to add classes, animations, etc. once it es into view.
I'm trying to get the same effect for the horizontal layout, but to no avail.
Here is the regular version of the function -
$.fn.isInViewport = function() {
if ( $(this).length ) {
var elementTop = $(this).offset().top;
}
var elementBottom = elementTop + $(this).outerHeight();
var viewportTop = $(window).scrollTop();
var viewportBottom = viewportTop + $(window).height();
return elementBottom > viewportTop && elementTop < viewportBottom;
};
And here is the way I tried it for horizontal layouts, which didn't work.
$.fn.isInViewport = function() {
if ( $(this).length ) {
var elementLeft = $(this).offset().left;
}
var elementRight = elementLeft + $(this).outerWidth();
var viewportLeft = $(window).scrollLeft();
var viewportRight = viewportLeft + $(window).width();
return elementRight > viewportLeft && elementLeft < viewportRight;
};
You call the function like so
$(".element").each(function() {
if ( $(this).isInViewport() ) {
$(this).addClass("animate-element");
}
});
Share
Improve this question
asked Jan 8, 2021 at 18:09
yermeyerme
8558 silver badges16 bronze badges
3
- 6 Check out the Intersection Observer API as long as you don't need IE patibility. – D M Commented Jan 8, 2021 at 18:13
-
1
The implementation for horizontal check is working fine jsfiddle/taLzu8er/1 . Only issue looks like is the variable
elementLeft
is defined inside if statement's scope. The declaration should be before the if statement. – the Hutt Commented Jan 17, 2022 at 16:18 -
@onkarruikar that would be correct if
let
was being used, but since it'svar
and there's only one function here, the scope is the same whether declared inside or outside theif
. (I agree it's still better declared outside though, since then the actual scope matches ones visual perceptions better.) – Robin Zigmond Commented Jan 17, 2022 at 20:19
2 Answers
Reset to default 4 +25Using jquery its pretty easy, All yo have to do is $(element).on('scroll',(--function--)) and then you can use $(this).offset().left to get the pixel on its left and when you get the offset of left, you can just do whatever you want. Check the snippet below for an working example. (if possible run in smaller screen like mobile)
$("#timeline").on('scroll', function() {
$("#timeline .each").each(function(){
let left = $(this).offset().left;
if(left >-50 && left< (window.innerWidth - 100)){
$(this).addClass('mvisible')
}
else{
if($(this).hasClass('mvisible')){
$(this).removeClass('mvisible')
}
}
});
});
.timeline{overflow-x:auto;width:100%}
.timeline .warp{display:flex;width:1600px;padding:50px 100px 50px 30px;}
.timeline .each{width:185px;}
.timeline .desc{padding:15px;border-radius:4px;background:#08f;color:#fff;width:100%;transform:translateY(50px);opacity:0;transition:0.4s}
.timeline .mvisible .desc{transform:translateY(0);opacity:1}
<script src="https://cdnjs.cloudflare./ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="timeline" id="timeline">
<div class="warp">
<div class="each mvisible">
<div class="desc">
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
</div>
</div>
<div class="each">
<div class="desc">
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
</div>
</div>
<div class="each">
<div class="desc">
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
</div>
</div>
<div class="each" >
<div class="desc">
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
</div>
</div>
<div class="each" >
<div class="desc">
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
</div>
</div>
<div class="each">
<div class="desc">
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
</div>
</div>
<div class="each">
<div class="desc">
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
</div>
</div>
<div class="each">
<div class="desc">
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
</div>
</div>
</div>
</div>
As mentioned in the ments IntersectionObserver is a good place to start
const inViewObserver = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
// do stuff when in view
entry.target.classList.add('in-view')
document.body.dataset.log = 'Element in view - well done