yerme
yerme

Reputation: 855

Check if element is in viewport based on horizontal scroll

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 comes 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");
    }
});

Upvotes: 3

Views: 3558

Answers (2)

Jakob E
Jakob E

Reputation: 4926

As mentioned in the comments 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 😃'
    } else {
      // do stuff when not in view
      entry.target.classList.remove('in-view')
      document.body.dataset.log = 'Element not in view - try to find it 🔍'
    }
  })
}, { threshold: .5 })

const elm = document.querySelector('.element')
inViewObserver.observe(elm)
body {
  /* trigger scroll in both directions */
  width: 300vw;
  height: 300vh;
  display: grid;
  place-items: center;
}

body::before {
  content: attr(data-log);
  position: fixed;
  top: 0;
  left: 0;
}

.element {
  background: tomato;
  width: 10rem;
  height: 10rem;
  transition: all 600ms 300ms;
  transform: scale(0.25) rotate(360deg);
}

.in-view {
  background: olive;
  transform: none;
  border-radius: 1rem; 
}
<div class="element"></div>

Upvotes: 2

Ashiq Dey
Ashiq Dey

Reputation: 511

Using 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.com/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>

Upvotes: 4

Related Questions