This is a bit of JavaScript (jQuery) I wrote that shrinks an element to be as high as possible while still keeping the entire page above the fold. The way it works is essentially "calculate the height difference between the document and the window, and make the element smaller by that much". (see below.)
This works fine as far as I can tell — except that unfortunately I still need IE7 support, and the behavior in that browser is kind of wonky. Specifically, calling my function seems to fire another resize event, causing a kind of feedback loop.
IE7 is apparently the only browser this happens in, and I haven't yet figured out why it happens. I've already tried making the target height smaller to make sure nothing goes out of bounds, but the result is the same.
What's the best way to make my code not fire the resize event in IE7?
function stretchToBottom($element) {
(window.onresize = function () {
// temporarily reset the element's height so $(document).height() yields the right value
$element.css({maxHeight: ''});
var heightDiff = $(document).height() - $(window).height();
if (heightDiff <= 0) {
return;
}
var initialHeight = $element[0].scrollHeight;
var minHeight = 200;
var targetHeight = initialHeight - heightDiff;
var height = Math.max(targetHeight, minHeight);
$element.css({maxHeight: height + 'px'});
})();
}
wrap your code with:
<!--[if !IE7]>-->
//NONE IE code comes here
<!--<![endif]-->
<!--[if IE7]>
//ONLY IE7 code comes here
<![endif]-->
more info here
I just discovered this question which describes the exact same problem I have. The top two answers offered a working solution: store the current window dimensions and process the event listener only when they have actually changed.
For the record, here's the working code I currently have. I changed the function name to be more accurate and moved the "add event listener" part to outside the function.
function shrinkToFit($element) {
$element.css({maxHeight: ''});
var heightDiff = $(document).height() - $(window).height();
if (heightDiff <= 0) {
return;
}
var initialHeight = $element[0].scrollHeight;
var minHeight = 200;
var targetHeight = initialHeight - heightDiff;
var height = Math.max(targetHeight, minHeight);
$element.css({maxHeight: height + 'px'});
}
var lastWindowWidth = $(window).width();
var lastWindowHeight = $(window).height();
$(window).on('resize', function () {
if (lastWindowWidth !== $(window).width() || lastWindowHeight !== $(window).height()) {
shrinkToFit($tableContainer);
lastWindowWidth = $(window).width();
lastWindowHeight = $(window).height();
}
});
I've got a problem with creating a transition for a collapsing text-jquery plugin I've found. Unfortunatley I've go almost no understanding to javascript. At the bottom I added "&&(this).show('fast');" but it didn't work. Hopefully you can help.
$(document).ready(function () {
var maxheight=16;
var showText="Weiterlesen";
var hideText="Zusammenklappen";
$('.expand').each(function () {
var text = $(this);
if (text.height() > maxheight){
text.css({ 'overflow':'hidden','height': maxheight + 'px' });
var link = $('<p class="weiter" id="noselect"><a>' + showText + '</a></p>');
var linkDiv = $('<div></div>');
linkDiv.append(link);
$(this).after(linkDiv);
link.click(function (event) {
event.preventDefault();
if (text.height() > maxheight) {
$(this).html('<a>' + showText + '</p>');
text.css('height', maxheight + 'px')
&&(this).show('fast');
} else {
$(this).html('<a>' + hideText + '</p>');
text.css('height', 'auto')
&&(this).show('fast');
}
});
}
});
});
Try Changing it to this
$(this).html('<a>' + hideText + '</p>');
text.css('height', 'auto');
$(this).show('fast');
This is using the correct JQuery syntax, wether it works or not depends on what "this" is.
(this).show();
wont work. this is an HTML Element , and it has no show property. You want the jquerys object property.
jQuery(this)//get the jquery object of that html el
.show();//call the function on that
$ is just a shortform of jQuery. So:
$(this).show();
Note this is the link, but you want to show the text (wich is already a jquery object):
text.show();
Concerning the && ( the AND operator):
false && alert("nope");
true && alert("yes");
a() && b(); //b is just called if a() is truthy => can create bugs in your case
Ita not neccessary / useful to use this operator here. However, you could use the Comma operator, but its common to simply use two statements...
However, if ive got you right, its not neccessary to show but rather to add a transition. That can be done with css:
.expand{
transition:all 2s ease;
}
Note this doesnt work for height, but for max-height, so one may set height:auto and change max height from 0px to 500%...
I'm creating a website and I have a problem with IE compatibility. My idea to fix this is to have a JQuery script that changes the images width proportional to the window.
However, my script isn't working.
$(document).read(function() {
updateSizes();
$(window).resize(function() {
updateSizes();
})
});
function updateSizes() {
var $windowHeight = $(window).height();
var $windowWidth = $(window).width();
$(".fadingImg").css("width",$windowWidth * 0.7)
}
I have tried adding + "px" to $(".fadingImg").css("width",$windowWidth * 0.7)
My JQuery implementation is:
<script src="http://abrahamyan.com/wp-content/uploads/2010/jsslideshow/js/jquery-1.4.3.js" type="text/javascript"></script>
It should be
$(document).ready(function() {
not
$(document).read
You need to add px but in the right place
$(".fadingImg").css("width", ($windowWidth * 0.7) + "px")
You also need to make sure that you have class="fadingImg"
You also need to make sure that you put it within a ready block
$(function() {
//code here
});
Instead of using JavaScript for this solution, why not use CSS?
.fadingImg { width: 70%; }
if your fadingImg is a <img>, then try to set the attribute
$(".fadingImg").attr("width",$windowWidth * 0.7)
I am faking fixed position for a footer on a mobile site for mobile browsers that don't support fixed-position. (iOS before iOS 5, Andriod before 2.2, etc.)
Here is the JQuery code I'm using, which works well and does what I want:
function changeFooterPosition() {
$('.not-fixed').css('top', window.innerHeight + window.scrollY - 56 + "px");
}
$(document).bind('scroll', function() {
changeFooterPosition();
});
So that works.
My question is, I want to add a slight delay to it and have the footer fade into view rather than just snap quickly after every little scroll. I've looked around and found the following methods I could use, but I"m not sure if they are the correct ones or where to add them to the js above.
.delay(1000).fadeTo('slow', 1)
I know this functionality exists in JQuery Mobile, but I don't want to use the entirety of JQuery Mobile for just this one little thing.
Thanks in advance.
Try the animate function http://api.jquery.com/animate/
This won't fade but should move smoothly instead.
function changeFooterPosition() {
$('.not-fixed').animate({'top': window.innerHeight + window.scrollY - 56 + "px"}, 2000);
}
$(document).bind('scroll', changeFooterPosition);
Change
$(document).bind('scroll', function() {
changeFooterPosition();
});
To
$(document).bind('scroll', changeFooterPosition);
Change
$('.not-fixed').css('top', window.innerHeight + window.scrollY - 56 + "px");
to
var WantedSpeed = 2000;
$('.not-fixed').delay(1000).animate({
top: window.innerHeight + window.scrollY - 56 + "px"
}, WantedSpeed, function() {
// Animation complete.
})
What you want to do is throttle your scroll callback:
(function() {
var scrollTimer = 0,
$notFixed = $('.not-fixed');
function changeFooterPosition() {
$notFixed.css('top', window.innerHeight + window.scrollY - 56 + "px").show(300);
}
$(document).bind('scroll', function() {
$notFixed.hide();
clearTimeout(scrollTimer);
setTimeout(changeFooterPosition, 50);
});
}());
This question already has answers here:
How to detect if browser window is scrolled to bottom?
(23 answers)
Closed 1 year ago.
The community reviewed whether to reopen this question 15 days ago and left it closed:
Original close reason(s) were not resolved
I'm making a pagination system (sort of like Facebook) where the content loads when the user scrolls to the bottom. I imagine the best way to do that is to find when the user is at the bottom of the page and run an Ajax query to load more posts.
The only problem is I don't know how to check if the user has scrolled to the bottom of the page. Any ideas?
I'm using jQuery, so feel free to provide answers that use it.
Use the .scroll() event on window, like this:
$(window).scroll(function() {
if($(window).scrollTop() + $(window).height() == $(document).height()) {
alert("bottom!");
}
});
You can test it here, this takes the top scroll of the window, so how much it's scrolled down, adds the height of the visible window and checks if that equals the height of the overall content (document). If you wanted to instead check if the user is near the bottom, it'd look something like this:
$(window).scroll(function() {
if($(window).scrollTop() + $(window).height() > $(document).height() - 100) {
alert("near bottom!");
}
});
You can test that version here, just adjust that 100 to whatever pixel from the bottom you want to trigger on.
TL;DR;
Math.abs(element.scrollHeight - element.scrollTop - element.clientHeight) < 1
Concept
At its core, "having scrolled to the bottom" refers to the moment when the scrollable area (scrollHeight) minus the distance of the visible content from the top (scrollTop) equals the height of the visible content (clientHeight).
Differently put, we are "scrolled" when this equivalence is true::
scrollHeight - scrollTop - clientHeight === 0
Preventing Rounding Error
As mentioned however, some of these properties are rounded, which means that the equality can fail in cases where scrollTop would have a decimal component or when the rounded values align poorly.
It is possible to mitigate that problem by comparing the absolute difference to a tolerable threshold:
Math.abs(element.scrollHeight - element.clientHeight - element.scrollTop) < 1
A snippet that prevents rouding error could look like this:
document.getElementById('constrained-container').addEventListener('scroll', event => {
const {scrollHeight, scrollTop, clientHeight} = event.target;
if (Math.abs(scrollHeight - clientHeight - scrollTop) < 1) {
console.log('scrolled');
}
});
#constrained-container {
height: 150px;
overflow-y: scroll;
}
#very-long-content {
height: 600px;
}
<div id="constrained-container">
<div id="very-long-content">
scroll me to the bottom
</div>
</div>
Note that I've added a div that is too big for its container to force the scrolling but there's no need to "wrap" the content in another element, text directly in an element would make the element overflow.
Debouncing, Delaying and Throttling
The more I understand about it and the less I find it's within the scope of this answer (this codereview question and its answer, and this linked article are of interest), but in specific cases (if the handler does expensive computation, if we tie an animation to the scroll event, if we only want to launch the event at the end of the scroll motion, or any situation that may warrants it) it can be useful to:
debounce (fire the handler when the first scroll happen, then prevent it from firing too fast),
delay (prevent the execution of the handler until the scroll event wasn't fired for a period of time. this is often called debouncing in Ecmascript context),
or throttle (preventing the handler to fire more than once every period of time).
Great care must be taken in choosing to do any of these things, for instance throttling the event could prevent the last scroll to fire, which could completely defeat an infinite scroller.
Not doing any of those three things works perfectly fine most of the time, as just looking if we're completely scrolled is relatively inexpensive.
Nick Craver's answer works fine, spare the issue that the value of $(document).height() varies by browser.
To make it work on all browsers, use this function from James Padolsey:
function getDocHeight() {
var D = document;
return Math.max(
D.body.scrollHeight, D.documentElement.scrollHeight,
D.body.offsetHeight, D.documentElement.offsetHeight,
D.body.clientHeight, D.documentElement.clientHeight
);
}
in place of $(document).height(), so that the final code is:
$(window).scroll(function() {
if($(window).scrollTop() + $(window).height() == getDocHeight()) {
alert("bottom!");
}
});
Further to the excellent accepted answer from Nick Craver, you can throttle the scroll event so that it is not fired so frequently thus increasing browser performance:
var _throttleTimer = null;
var _throttleDelay = 100;
var $window = $(window);
var $document = $(document);
$document.ready(function () {
$window
.off('scroll', ScrollHandler)
.on('scroll', ScrollHandler);
});
function ScrollHandler(e) {
//throttle event:
clearTimeout(_throttleTimer);
_throttleTimer = setTimeout(function () {
console.log('scroll');
//do work
if ($window.scrollTop() + $window.height() > $document.height() - 100) {
alert("near bottom!");
}
}, _throttleDelay);
}
Nick Craver's answer needs to be slightly modified to work on iOS 6 Safari Mobile and should be:
$(window).scroll(function() {
if($(window).scrollTop() + window.innerHeight == $(document).height()) {
alert("bottom!");
}
});
Changing $(window).height() to window.innerHeight should be done because when the address bar is hidden an additional 60px are added to the window's height but using $(window).height() does not reflect this change, while using window.innerHeight does.
Note: The window.innerHeight property also includes the horizontal scrollbar's height (if it is rendered), unlike $(window).height() which will not include the horizontal scrollbar's height. This is not a problem in Mobile Safari, but could cause unexpected behavior in other browsers or future versions of Mobile Safari. Changing == to >= could fix this for most common use cases.
Read more about the window.innerHeight property here
Here's a fairly simple approach
const didScrollToBottom = elm.scrollTop + elm.clientHeight == elm.scrollHeight
Example
elm.onscroll = function() {
if(elm.scrollTop + elm.clientHeight == elm.scrollHeight) {
// User has scrolled to the bottom of the element
}
}
Where elm is an element retrieved from i.e document.getElementById.
Please check this answer
window.onscroll = function(ev) {
if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight) {
console.log("bottom");
}
};
You can do footerHeight - document.body.offsetHeight to see if you are near the footer or reached the footer
Here is a piece of code that will help you debug your code, I tested the above answers and found them to be buggy. I have test the followings on Chrome, IE, Firefox, IPad(Safari). I don't have any others installed to test...
<script type="text/javascript">
$(function() {
$(window).scroll(function () {
var docElement = $(document)[0].documentElement;
var winElement = $(window)[0];
if ((docElement.scrollHeight - winElement.innerHeight) == winElement.pageYOffset) {
alert('bottom');
}
});
});
</script>
There may be a simpler solution, but I stopped at the point at which IT WORKED
If you are still having problems with some rogue browser, here is some code to help you debug:
<script type="text/javascript">
$(function() {
$(window).scroll(function () {
var docElement = $(document)[0].documentElement;
var details = "";
details += '<b>Document</b><br />';
details += 'clientHeight:' + docElement.clientHeight + '<br />';
details += 'clientTop:' + docElement.clientTop + '<br />';
details += 'offsetHeight:' + docElement.offsetHeight + '<br />';
details += 'offsetParent:' + (docElement.offsetParent == null) + '<br />';
details += 'scrollHeight:' + docElement.scrollHeight + '<br />';
details += 'scrollTop:' + docElement.scrollTop + '<br />';
var winElement = $(window)[0];
details += '<b>Window</b><br />';
details += 'innerHeight:' + winElement.innerHeight + '<br />';
details += 'outerHeight:' + winElement.outerHeight + '<br />';
details += 'pageYOffset:' + winElement.pageYOffset + '<br />';
details += 'screenTop:' + winElement.screenTop + '<br />';
details += 'screenY:' + winElement.screenY + '<br />';
details += 'scrollY:' + winElement.scrollY + '<br />';
details += '<b>End of page</b><br />';
details += 'Test:' + (docElement.scrollHeight - winElement.innerHeight) + '=' + winElement.pageYOffset + '<br />';
details += 'End of Page? ';
if ((docElement.scrollHeight - winElement.innerHeight) == winElement.pageYOffset) {
details += 'YES';
} else {
details += 'NO';
}
$('#test').html(details);
});
});
</script>
<div id="test" style="position: fixed; left:0; top: 0; z-index: 9999; background-color: #FFFFFF;">
I hope this will save someone some time.
var elemScrolPosition = elem.scrollHeight - elem.scrollTop - elem.clientHeight;
It calculates distance scroll bar to bottom of element.
Equal 0, if scroll bar has reached bottom.
This is my two cents:
$('#container_element').scroll( function(){
console.log($(this).scrollTop()+' + '+ $(this).height()+' = '+ ($(this).scrollTop() + $(this).height()) +' _ '+ $(this)[0].scrollHeight );
if($(this).scrollTop() + $(this).height() == $(this)[0].scrollHeight){
console.log('bottom found');
}
});
Here is a vanilla JavaScript solution that uses ES 6 and debounce:
document.addEventListener('scroll', debounce(() => {
if(document.documentElement.scrollHeight === window.pageYOffset + window.innerHeight) {
// Do something
}
}, 500))
function debounce(e,t=300){let u;return(...i)=>{clearTimeout(u),u=setTimeout(()=>{e.apply(this,i)},t)}}
Demo: https://jsbin.com/jicikaruta/1/edit?js,output
References:
scrollHeight
pageYOffset
innerHeight
Debounce
My solution in plain js:
let el=document.getElementById('el');
el.addEventListener('scroll', function(e) {
if (this.scrollHeight - this.scrollTop - this.clientHeight<=0) {
alert('Bottom');
}
});
#el{
width:400px;
height:100px;
overflow-y:scroll;
}
<div id="el">
<div>content</div>
<div>content</div>
<div>content</div>
<div>content</div>
<div>content</div>
<div>content</div>
<div>content</div>
<div>content</div>
<div>content</div>
<div>content</div>
<div>content</div>
</div>
Instead of listening to the scroll event, using Intersection Observer is the inexpensive one for checking if the last element was visible on the viewport (that's mean user was scrolled to the bottom). It also supported for IE7 with the polyfill.
var observer = new IntersectionObserver(function(entries){
if(entries[0].isIntersecting === true)
console.log("Scrolled to the bottom");
else
console.log("Not on the bottom");
}, {
root:document.querySelector('#scrollContainer'),
threshold:1 // Trigger only when whole element was visible
});
observer.observe(document.querySelector('#scrollContainer').lastElementChild);
#scrollContainer{
height: 100px;
overflow: hidden scroll;
}
<div id="scrollContainer">
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
<div>Item 4</div>
<div>Item 5</div>
<div>Item 6</div>
<div>Item 7</div>
<div>Item 8</div>
<div>Item 9</div>
<div>Item 10</div>
</div>
Nick answers its fine but you will have functions which repeats itsself while scrolling or will not work at all if user has the window zoomed. I came up with an easy fix just math.round the first height and it works just as assumed.
if (Math.round($(window).scrollTop()) + $(window).innerHeight() == $(document).height()){
loadPagination();
$(".go-up").css("display","block").show("slow");
}
In case someone wants a vanilla JavaScript solution and needs to detect when a user has scrolled to the bottom of a <div> I managed to implement it by using these lines of code
window.addEventListener("scroll", () => {
var offset = element.getBoundingClientRect().top - element.offsetParent.getBoundingClientRect().top;
const top = window.pageYOffset + window.innerHeight - offset;
if (top === element.scrollHeight) {
console.log("bottom");
}
}, { passive: false });
I Have done this very easy way with pure JS.
function onScroll() {
if (window.pageYOffset + window.innerHeight >= document.documentElement.scrollHeight - 50) {
Console.log('Reached bottom')
}
}
window.addEventListener("scroll", onScroll);
All these solutions doesn't work for me on Firefox and Chrome, so I use custom functions from Miles O'Keefe and meder omuraliev like this:
function getDocHeight()
{
var D = document;
return Math.max(
D.body.scrollHeight, D.documentElement.scrollHeight,
D.body.offsetHeight, D.documentElement.offsetHeight,
D.body.clientHeight, D.documentElement.clientHeight
);
}
function getWindowSize()
{
var myWidth = 0, myHeight = 0;
if( typeof( window.innerWidth ) == 'number' ) {
//Non-IE
myWidth = window.innerWidth;
myHeight = window.innerHeight;
} else if( document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) {
//IE 6+ in 'standards compliant mode'
myWidth = document.documentElement.clientWidth;
myHeight = document.documentElement.clientHeight;
} else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {
//IE 4 compatible
myWidth = document.body.clientWidth;
myHeight = document.body.clientHeight;
}
return [myWidth, myHeight];
}
$(window).scroll(function()
{
if($(window).scrollTop() + getWindowSize()[1] == getDocHeight())
{
alert("bottom!");
}
});
You can try the following code,
$("#dashboard-scroll").scroll(function(){
var ele = document.getElementById('dashboard-scroll');
if(ele.scrollHeight - ele.scrollTop === ele.clientHeight){
console.log('at the bottom of the scroll');
}
});
Try this for match condition if scroll to bottom end
if ($(this)[0].scrollHeight - $(this).scrollTop() ==
$(this).outerHeight()) {
//code for your custom logic
}
This gives accurate results, when checking on a scrollable element (i.e. not window):
// `element` is a native JS HTMLElement
if ( element.scrollTop == (element.scrollHeight - element.offsetHeight) )
// Element scrolled to bottom
offsetHeight should give the actual visible height of an element (including padding, margin, and scrollbars), and scrollHeight is the entire height of an element including invisible (overflowed) areas.
jQuery's .outerHeight() should give similar result to JS's .offsetHeight --
the documentation in MDN for offsetHeight is unclear about its cross-browser support. To cover more options, this is more complete:
var offsetHeight = ( container.offsetHeight ? container.offsetHeight : $(container).outerHeight() );
if ( container.scrollTop == (container.scrollHeight - offsetHeight) ) {
// scrolled to bottom
}
i used this test to detect the scroll reached the bottom:
event.target.scrollTop === event.target.scrollHeight - event.target.offsetHeight
Safari can scroll past the bottom of the page which was causing a bug in our application. Solve this using >= instead of ===.
container.scrollTop >= container.scrollHeight - container.clientHeight
Here's my two cents as the accepted answer didn't work for me.
var documentAtBottom = (document.documentElement.scrollTop + window.innerHeight) >= document.documentElement.scrollHeight;
Google Chrome gives the full height of the page if you call $(window).height()
Instead, use window.innerHeight to retrieve the height of your window.
Necessary check should be:
if($(window).scrollTop() + window.innerHeight > $(document).height() - 50) {
console.log("reached bottom!");
}
Many other solutions doesn't work for me Because on scroll to bottom my div was triggering the alert 2 times and when moving up it was also trigerring upto a few pixels so The solution is:
$('#your-div').on('resize scroll', function()
{
if ($(this).scrollTop() +
$(this).innerHeight() >=
$(this)[0].scrollHeight + 10) {
alert('reached bottom!');
}
});
Here is the most simple way to do it:
const handleScroll = () => {
if (window.innerHeight + window.pageYOffset >= document.body.offsetHeight) {
console.log('scrolled to the bottom')
}}
window.addEventListener('scroll', handleScroll)
(2021)
Lots of answers here involve a ref to an element, but if you only care about the whole page, just use:
function isBottom() {
const { scrollHeight, scrollTop, clientHeight } = document.documentElement;
const distanceFromBottom = scrollHeight - scrollTop - clientHeight;
return distanceFromBottom < 20; // adjust the number 20 yourself
}
Let me show approch without JQuery. Simple JS function:
function isVisible(elem) {
var coords = elem.getBoundingClientRect();
var topVisible = coords.top > 0 && coords.top < 0;
var bottomVisible = coords.bottom < shift && coords.bottom > 0;
return topVisible || bottomVisible;
}
Short example how to use it:
var img = document.getElementById("pic1");
if (isVisible(img)) { img.style.opacity = "1.00"; }
I used #ddanone answear and added Ajax call.
$('#mydiv').on('scroll', function(){
function infiniScroll(this);
});
function infiniScroll(mydiv){
console.log($(mydiv).scrollTop()+' + '+ $(mydiv).height()+' = '+ ($(mydiv).scrollTop() + $(mydiv).height()) +' _ '+ $(mydiv)[0].scrollHeight );
if($(mydiv).scrollTop() + $(mydiv).height() == $(mydiv)[0].scrollHeight){
console.log('bottom found');
if(!$.active){ //if there is no ajax call active ( last ajax call waiting for results ) do again my ajax call
myAjaxCall();
}
}
}
To stop repeated alert of Nick's answer
ScrollActivate();
function ScrollActivate() {
$(window).on("scroll", function () {
if ($(window).scrollTop() + $(window).height() > $(document).height() - 100) {
$(window).off("scroll");
alert("near bottom!");
}
});
}