Skip to content Skip to sidebar Skip to footer

Add Class To Element When Scrolled Into View (scrollable Div)

Is there a solution for adding a class to the element in view when scrolling, and removing when out of view? This needs to work for a scrollable div. I have found a few solutions s

Solution 1:

You could make your own jQuery plugin to do this. Something like this which takes two functions (whenInView, whenNotInView):

$('.journal-slider .each-slide img').inViewport(
    function(){$(this).addClass("am-in-view");},
    function(){$(this).removeClass("am-in-view");}
);

It tests on scroll (or resize) wether the target elements are currently within the viewport and calls the related function.

Here's the whole thing as a demo Snippet. In this example I have added an animation to the .am-in-view class so that you can see it working as the elements enter the viewport. This has not been tested on anything other than Chrome so far. Feel free to use and improve.

/*! inViewport 0.0.1 
 *  jQuery plugin by Moob
 * ======================== 
 *  (requires jQuery) 
 */  
(function ($) {

    var vph=0;
    functiongetViewportDimensions(){
        vph = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
    }
    getViewportDimensions();    
    //on resize/scroll
    $(window).on('resize orientationChanged', function(){
        getViewportDimensions();
    });            
    
    $.fn.inViewport = function (whenInView, whenNotInView) {                  
        returnthis.each(function () {
            var el = $(this),
                inviewalreadycalled = false,
                notinviewalreadycalled = false;                            
            //on resize/scroll
            $(window).on('resize orientationChanged scroll', function(){
                checkInView();
            });               
            functioncheckInView(){
                var rect = el[0].getBoundingClientRect(),
                    t = rect.top,
                    b = rect.bottom;
                if(t<vph && b>0){
                    if(!inviewalreadycalled){
                        whenInView.call(el);
                        inviewalreadycalled = true;
                        notinviewalreadycalled = false;
                    }
                } else {
                    if(!notinviewalreadycalled){
                        whenNotInView.call(el);
                        notinviewalreadycalled = true;
                        inviewalreadycalled = false;
                    }
                }
            }
            //initial checkcheckInView();                
        });
    }             
}(jQuery));
html, body {
    margin:0;
}
.me, .not-me {
    padding:20px;
    border:1px solid #aaa;
    margin:20px;
}
.am-in-view {
    background-color:pink;
    -webkit-transition: all 1500ms;
    -moz-transition: all 1500ms;
    -o-transition: all 1500ms;
    transition: all 1500ms;
}
<scriptsrc="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script><divclass="me"><p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Eveniet, pariatur.</p><p>Saepe, eligendi nihil totam dolorum reprehenderit! Repellat omnis neque quasi.</p><p>Eos cumque voluptatum placeat eius nisi facere neque nesciunt praesentium.</p><p>Eos qui consectetur voluptatem eum, labore accusamus tempora distinctio sunt?</p></div><divclass="me"><p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Excepturi, sit.</p><p>A veritatis quis quae totam accusamus repellendus adipisci corporis soluta.</p><p>Debitis animi dolor distinctio ratione dolorum ex aperiam maiores fugit?</p><p>Incidunt non consequatur porro provident recusandae sunt architecto repellat enim.</p></div><divclass="me"><p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis, reprehenderit?</p><p>Neque tempora perferendis dolor, mollitia debitis sunt voluptas ea ut!</p><p>Maiores earum officia corporis, sint voluptatem, in laboriosam perferendis asperiores?</p><p>Odit dolor voluptate laboriosam voluptatem accusamus aperiam explicabo at provident.</p></div><divclass="not-me"><p>I'm totally normal</p></div><divclass="me"><p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ullam, accusamus.</p><p>Quisquam architecto repellat facere amet sapiente dolore obcaecati harum fuga.</p><p>Tempora labore, unde necessitatibus ipsam repellat architecto, aliquam autem at.</p><p>Sapiente quis doloremque a illum, repellat, eius corporis ab placeat.</p></div><divclass="me"><p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Voluptate, assumenda!</p><p>Nesciunt corrupti, eaque dolores ut libero ipsam dolorem laudantium saepe.</p><p>Similique quisquam quod esse expedita, voluptate quia nobis? Cum, tempore.</p><p>Amet voluptatem eaque non, praesentium tenetur molestias minima architecto laboriosam?</p></div><divclass="me"><p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tempore, ex?</p><p>Perferendis hic, sint maxime similique quia autem cum quasi? Sed.</p><p>Nemo ratione aliquid itaque est blanditiis aliquam maiores veniam ab!</p><p>Reiciendis cumque fugit earum ea animi et aut molestiae dolores!</p></div><!-- how to call it --><script>
    $(function(){
      
        $('.me').inViewport(
            function(){$(this).addClass("am-in-view");},
            function(){$(this).removeClass("am-in-view");}
        );
      
    });
</script>

Solution 2:

The plugin you are looking for is called waypoints

Quote from the "Get Started" :

"Let's say you have a div with overflow:scroll, and you want a waypoint inside of this scrollable element. The context option lets you do this. Scroll the box below."

$('#example-context').waypoint(function() {
    notify('Hit top of context');
}, { context: '.example-scroll-div' });

EDIT: Not using waypoints

Based on what you already did, I came to this :

functioncheckInView(elem,partial)
{
    var container = $(".scrollable");
    var contHeight = container.height();
    var contTop = container.scrollTop();
    var contBottom = contTop + contHeight ;
 
    var elemTop = $(elem).offset().top - container.offset().top;
    var elemBottom = elemTop + $(elem).height();

    var isTotal = (elemTop >= 0 && elemBottom <=contHeight);
    var isPart = ((elemTop < 0 && elemBottom > 0 ) || (elemTop > 0 && elemTop <= container.height())) && partial ;

    return  isTotal  || isPart ;
}

$(document).ready(function(){
$(".scrollable").scroll(function(){
    var result="",result2="";
   $.each( $(".scrollable p"),function(i,e){
       if (checkInView($(e),false)) {
           $( this ).addClass( "red" );
       } else {
           $( this ).removeClass( "red" );
       }
        result += " " +  checkInView($(e),false);
       result2 += " " +  checkInView($(e),true);
    });
    $("#tt").text(result);
    $("#kk").text(result2);
});
});
.scrollable{
    margin:10px;
    height:100px;
    overflow-y:scroll;
}
p
{
    border-width:1px;
    border-color:black;
    border-style:solid;
}
.red {
    background-color: red;
}
<scriptsrc="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
full:  <divid="tt"></div>
part: <divid="kk"></div><divclass="scrollable"><p>item1<span></span></p><p>item2<span></span></p><p>item3<span></span></p><p>item4<span></span></p><p>item5<span></span></p><p>item6<span></span></p><p>item7<span></span></p><p>item8<span></span></p></div>

Solution 3:

where offset is an element's offset from screen. you should call this (throttles) using the scroll event, the repeatedly check if an element is in view.

functionisElementInViewport(el, offset){
        var rect = el.getBoundingClientRect();
        offset = offset || 0;

        return (
            rect.top - offset >= 0 &&
            rect.left >= 0 &&
            rect.bottom + offset <= (window.innerHeight || document.documentElement.clientHeight) && /*or $(window).height() */
            rect.right <= (window.innerWidth || document.documentElement.clientWidth) /*or $(window).width() */
        );
 }

using with onscroll event:

// utilizing underscore's `debounce` method
$(window).on('scroll.checkVisibility', _.debounce(check, 200));

functioncheck(){
    var visibility = isElementInViewport(element, -100);
    if( visibility )
       // do something if visisble

}

Solution 4:

Using the Intersection Observer API

(native on modern browsers)


As jQuery is becoming obsolete, here is a simple solution using the Intersection Observer API:

/* Javascript */// define an observer instancevar observer = newIntersectionObserver(onIntersection, {
  root: null, // default is the viewportthreshold: 0.5, // percentage of taregt's visible area. Triggers "onIntersection"
});

// callback is called on intersection changefunctiononIntersection(entries, opts) {
  entries.forEach((entry) => {
    if (entry.isIntersecting) {
      // Adding a class name if element is in view
      entry.target.classList.add("class-name");
    } else {
      // Removing the class name if element is NOT in view
      entry.target.classList.remove("class-name");
    }
  });
}

// Use the bserver to observe an element
observer.observe(document.getElementById("hello"));

// To stop observing:// observer.unobserve(entry.target)
/* CSS */#big-div {
  height: 600px;
}

.class-name {
  background-color: blue;
  transition: 2s background-color;
}
<!--HTML--><divid="big-div">Scroll down to see the result!</div><divid="hello">Hello world</div>

Post a Comment for "Add Class To Element When Scrolled Into View (scrollable Div)"