Reputation: 619
I want to get the percentage of an element (div) when its in viewport.
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?
Upvotes: 15
Views: 13272
Reputation: 4948
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');
Upvotes: 20
Reputation: 3127
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;
};
Upvotes: 5