13

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.stack.imgur.com/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?

youyoup
  • 559
  • 1
  • 6
  • 9

2 Answers2

17

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');
Nate
  • 4,718
  • 2
  • 25
  • 26
  • It's useful. My goal was to get the percentage when you scroll down, between : - when the element enter the viewport - when it's totally out (height of div included) of the viewport But your script will help me to do this – youyoup Nov 26 '13 at 21:09
  • Reversing it is extremely simple. I've updated my example: does it meet your need now? – Nate Nov 26 '13 at 21:13
  • I'm sorry for my poor english but you misunderstand my goal. here are five viewport of what I want. http://imgur.com/2ZPpps5 the pourcentage can't be 100% if the element is visible thanks you – youyoup Nov 26 '13 at 21:41
  • Indeed! Thanks for the graphic - that helps make what you want clearer. I've updated my example a second time. Does this do what you want? – Nate Nov 26 '13 at 21:58
  • I'm happy to hear it! – Nate Feb 13 '14 at 20:49
  • 1
    This only takes vertical percentage into account - if you make jsfiddle window narrow and reduce the width seen, the percentage is no longer accurate. But this algorithm is useful anyway! – Danger Feb 26 '15 at 16:55
  • modified the fiddle to show just the percent of element viewable to user in viewport. Percent decreases as you scroll downwards and element moves off the screen. http://jsfiddle.net/vinaynb/wp97g6cp/ – Vinay Jul 27 '16 at 13:22
  • @Danger More useful for vertical only in my case – David Callanan Feb 15 '20 at 17:45
5

My version is slightly different. When the element is higher than the screen height itself, it interprets that as 100% in viewport.

For example, if the screen height is 1000 pixels and the element is 2000 pixels height and it is scrolled fully into view, the function will return 100% instead of the normal 50%.

Enjoy.

var percentWithinViewport = function (element) {

    var elementTop = element.offset().top;
    var scrollTop = $(window).scrollTop();
    var spaceTop = elementTop - scrollTop;
    var elementHeight = element.height();
    var screenHeight = $(window).height();
    var scrollBottom = scrollTop + screenHeight;
    var bottomElement = elementTop + element.height();
    var spaceBottom = bottomElement - scrollBottom;
    var heightInScreen = elementHeight - spaceBottom;
    var percentage;

    if (spaceTop < 0) {
        heightInScreen -= spaceTop * -1;
    }

    if (spaceBottom < 0) {
        heightInScreen -= spaceBottom * -1;
    }

    percentage = heightInScreen / screenHeight * 100;
    percentage = percentage < 0 ? 0 : percentage;

    element.attr('data-percent-viewport', percentage);

    return percentage;
};
Floris
  • 2,727
  • 2
  • 27
  • 47