Search code examples
javascriptjqueryscrollviewportoffset

JS - get percentage of an element in Viewport


I want to get the percentage of an element (div) when its in viewport.

  • when the element enter the viewport I want the value of 0.
  • when the element and element's height leave the viewport I want the value of 100.

Here are 5 viewports of what I want to do https://i.sstatic.net/qaH97.jpg

I tried :

$(window).bind('scroll',function(){
var  viewportHeight = $(window).height(),
elementOffsetTop = $('#element').offset().top,
elementHeight = $('#element').height();

var numerator = 200 * (window.pageYOffset-elementOffsetTop+viewportHeight);
var denominator = (elementOffset+elementHeight+viewportHeight);
console.log(numerator/denominator);
});

This code works. (I don't understand why I have to multiply by 2).

But when I resize my page, this code not works ( value between 0 to 85 ... )

Ideas?


Solution

  • UPDATE: It seems like this still gets a little bit of traffic, so here's an updated solution that doesn't use jQuery.

    http://jsfiddle.net/nate/nmvka95j/20/

    const element = document.getElementById("element");
    const visible = document.getElementById("visible");
    
    const logPercentageSeen = () => {
      console.log(percentageSeen());
      visible.textContent = `${percentageSeen()} %`;
    };
    
    window.addEventListener("scroll", logPercentageSeen);
    
    const percentageSeen = () => {
      // Get the relevant measurements and positions
      const viewportHeight = window.innerHeight;
      const scrollTop = window.scrollY;
      const elementOffsetTop = element.offsetTop;
      const elementHeight = element.offsetHeight;
    
      // Calculate percentage of the element that's been seen
      const distance = scrollTop + viewportHeight - elementOffsetTop;
      const percentage = Math.round(
        distance / ((viewportHeight + elementHeight) / 100)
      );
    
      // Restrict the range to between 0 and 100
      return Math.min(100, Math.max(0, percentage));
    };
    
    // Log the initial value to the top before any scrolling has happened
    logPercentageSeen();
    

    Here's the old solution, pre-ES6 and using our old, dear friend jQuery.

    http://jsfiddle.net/nate/4N3Pj/1/

    var $element = $('#element');
    var $win = $(window);
    var $vis = $('#visible');
    
    $win.on('scroll', function () {
        console.log(percentageSeen());
        $vis.text(percentageSeen() + '%');
    });
    
    function percentageSeen () {
        var viewportHeight = $(window).height(),
            scrollTop = $win.scrollTop(),
            elementOffsetTop = $element.offset().top,
            elementHeight = $element.height();
    
    
        if (elementOffsetTop > (scrollTop + viewportHeight)) {
            return 0;
        } else if ((elementOffsetTop + elementHeight) < scrollTop) {
            return 100;
        } else {
            var distance = (scrollTop + viewportHeight) - elementOffsetTop;
            var percentage = distance / ((viewportHeight + elementHeight) / 100);
            percentage = Math.round(percentage);
            return percentage;
        }
    }
    
    $win.trigger('scroll');