How to detect when the height of your page changes? - javascript

I have a javascript heavy app which has widgets like autocomplete dropdowns and tabs and so forth. Sometimes when dropdowns appear and disappear, or when you switch between tabs, it changes the height of the document. This can cause annoyances if the scrollbar appears and disappears rapidly, because it shifts the page. I would like to detect when a page changes its height, so I can fix the height to the maximum so far, so that if the scrollbar appears it won't disappear only a second later. Any suggestions?
Update: onresize won't work because that's for changes in the size of the viewport/window - I want changes in the length of the document. I hadn't known about the watch function, looks like it will work at least for FF, but IE doesn't support it.

I belive this question has already been answered on stackoverflow here:
Detect Document Height Change
Basically you have to store the current document height and keep checking for a change via a timeoutcall
The element to watch here is document.body.clientHeight (or in jquery $(document).height() )

I think you can trap "onresize" events
here is a link to the w3schools.com description

You can user resize event to trap the change of the size of window using jquery as follows:
$(window).resize(function(){
// your code to check sizes and take action
}
);
Alternately you can track the change in document (not tested)
$(document).resize(function(){
// your code to check sizes and take action
}
);

One idea would be to use the watch() method on the clientHeight property:
document.body.watch("clientHeight", function(property, oldHeight, newHeight) {
// what you want to do when the height changes
});
The function you specify will get executed whenever the specified property changes. At any point you can use the unwatch() method to get it to stop.

Related

Disable Chrome's scroll preserving feature

I have a page containing a list of items:
Load more button should load some more items via ajax and append it to the items container preserving current scroll position. So after I click it the feed I expect it to look like this (green items are new):
But in fact Chrome 56 executes some computations to make the page stay in the same state, and what I see looks like this:
Is there any way to prevent this smart scrolling position setting in Chrome?
Update: I can reproduce the behavior only if parent container ('body' in my case) has 'display: flex' property (I use it to achieve 'sticky footer' feature).
I solved a similar problem by adding overflow-anchor: none; to the scroll container.
https://wicg.github.io/ScrollAnchoring/
Today it seems that this property was excluded? When adding 'overflow-anchor: none;' as style on a div element I get the message: Validation (CSS 3.0): "overflow-anchor" is not a known css property name.
This is simple. Before performing your AJAX call, save the scroll position of the page to a variable, then, after the call, scroll to the position indicated by that variable. Here is what you should write before your AJAX call:
var scrollpos = window.scrollY;
and here is the code after your AJAX call
window.scrollTo(0,scrollpos)
Hope this works
Why chrome makes calculations to preserve the scroll position? Usually the page will only be longer, so the scroll position stay fixed anyway.
I assume you remove the button, so the position cannot be kept, while content was not reloaded. You should reserve the button space in the dom and remove the reserved space when inserting the reloaded items.

Why does $(window).width() change while the page is loading?

I noticed that my scripts were setting widths incorrectly, so I tried the following snippet:
var prev;
setInterval(function(){
if($(window).width()!=prev)
console.log(prev=$(window).width());
},1);
This printed 2 different values: 1464 and 1481. Since these are 17px apart, I'm almost certain this is caused by scrollbars. The second value is the correct value.
Why does $(window).width() change without resizing the window? Shouldn't it return the browser window's width, which should be constant?
$(window).width() returns the width of the window object excluding scrollbars (otherwise known as the viewport width). Depending on the operating system and browser, the vertical scrollbar can often subtract from the viewport width. This means you should call this function once all your content has been loaded, and you'll need to call it again if the content changes.
Putting this in the $.ready() function won't guarantee that you'll get the correct width with respect to the final page content. This is because $.ready fires when the DOM is loaded, but there might still be images/fonts that can affect the layout. It's very possible that a scrollbar can get added after you call $.ready(). The easiest solution to this problem is to place your call inside the $(window).load() function instead, as this fires when all content has been loaded, and there's nothing more to render.
Generally speaking, it's a good idea to set the width on DOM ready, window load, window resize, and any time the content changes. This can be done like so:
$(function() {
var window_width;
function set_window_width() {
window_width = $(window).width();
// do something with window_width
}
set_window_width(); // set width on DOM ready
$(window).on('load resize', set_window_width); // set width on window load and resize
function custom_load_content() {
// load / change content
set_window_width();
}
});
Most (if not all) of the time, the viewport width is what you want. You're probably using the width to perform some calculations and/or resize some elements, and this should always be relative to the viewport, because your CSS is relative to the viewport. But, if for some reason you want to get the width including scrollbars, you can use window.innerWidth instead (source).
$(window).width() is affected by the margin, border and padding.
These can change as the DOM is being loaded.
As mentioned above, make sure you are waiting until $(document).ready() before you start looking at / twiddling with the DOM objects.
More info here http://api.jquery.com/width/
In most of the cases, the window width changes with the content, so there must be some ajax call coming which changes some content of the window. You can use browser debug tool and open the network traffic window to see what comes when the window width changes, debug into the javascript file to find which part of window changes with that ajax call, this may help you to find the reason.

How to get updated width of content after a css change?

I'm trying to modify the css class of my body element.
Before modifying the class, I check the scroll width of my content:
$(window.document.body).prop('scrollWidth'); // 800px
Now I modify the css class and check the scroll width again:
$(window.document.body).prop('class', someCssClassName);
$(window.document.body).prop('scrollWidth'); // still reports 800px
I know the scroll width should not be 800px after this particular change. I start a timer and keep printing the scroll width, and after a few ms I see it change to 600px.
So it seems like I can't immediately get the updated content width (or I'm misinterpreting what's going on).
Is there a way to get notified when the re-flow is complete, so that I might get the updated width?
I don't want to set a timer and keep checking, if possible.
I'm trying this in an android WebView.. browser.. . So I'm not sure if this behavior will be the same if I try in a desktop browser.
Thank you
To answer the question: accessing the scrollWidth property automatically flushes any style change (forces a reflow) and then returns the computed value. This happens synchronously, hence you don't need to "wait" for the reflow to complete -- the JS will simply freeze while the reflow happens and then return the correct scrollWidth value.
You are actually facing a very specific Blink/WebKit bug in their scrollWidth implementation regarding the body element.
I've simplified your code a bit by removing some unnecessary jQuery abstraction (fiddle):
document.body.className = 'w600px';
console.log(
document.body.scrollWidth, // Firefox: 600, Chrome: viewport width
$(document.body).width() // 600 in both browsers
);
.w600px {
width: 600px;
}
From the CSSOM element.scrollWidth spec:
3. If the element is the HTML body element, the Document is in quirks mode and the element has no associated scrolling box, return max(viewport scrolling area width, viewport width).
It seems like Chrome is not checking whether the document is in Quirks mode and returning the viewport (scrolling) width independent of the document mode.
You should open a Chromium issue in these cases.
Workarounds
It really depends on your use case. $(document.body).width() is usually fine, unless the content overflows the body element's width.
Alternatively, wrap all the page's contents inside of a div and use it to apply the class and to retrieve the scrollWidth from.
Try
function getprop( el, prop ) {
var props = window.getComputedStyle (
$(el).get(0)).getPropertyValue(prop);
return String(props);
};
console.log(getprop("body", "width"))
http://jsfiddle.net/guest271314/6uKH6/5/

How does one move html elements with scroll?

I want to create scroll behavior like what can be found here. If you scroll down the page you will notice the crabs, sharks, waves etc are animated whenever the page moves. How can this be achieved? Is this a script or CSS animation?
Edit: text bubbles also appear and disappear at different scroll points.
If you would like a more robust jQuery script to help you out: Per the answer at Loading a long page with multiple backgrounds based on vertical scroll value in jQuery?:
A slightly more full fat solution to the already great one suggested
by Justin is to use jQuery Waypoints to manage the in viewport events.
...
(the answer by Nicholas Evens)
It is a script, just bind a function to the window 'scroll' event with a callback function to do whatever you want. You can tell how far you've scrolled with window.scrollY.
$(window).bind('scroll', function () {
console.log(window.scrollY);
});
You need to subscribe scroll event using jQuery and move your element basing on the scrolling offset whitch can be reached using .scrollTop() property
$(window).scroll(function () {
var scrollOffset = $(this).scrollTop();
// move element to the offcet
});
I didn't look at the site's source code, but I believe it depends on JS. Javascript is necessary to listen to the scroll event of the page, and act according to the current value of document.scrollTop. Then the elements can be positioned with JS, and images can be switched either directly in JS, or by using CSS to change some element's CSS class.
That is definitly a script, you can attach an onscroll event and get the percentage of the current scroll and just position your "crabs" depending on that.
There was already a lot of scripts of how to get the percentage here

Use jQuery to mirror height of a dynamic element

I have a sidebar on my page that I want to always be 100% of the container size. Sadly, I can't tell the element to do this via CSS alone as the page has a variable height due to dynamic content.
Is it possible to use jQuery to find the height of the content container, and adjust the sidebar height to match it?
I found a few jQuery plugins that kind of do what I want, but feel they are over complicated (and I can't seem to get them to work anyway!).
Assuming the id of your container is "container" and the id of your sidebar is "sidebar", you could try the following (untested!)
$(document).ready(function() {
$('#sidebar').height($('#container').height());
});
This should (on document load), resize the sidebar height to the same as the container height.
I'm going to continue on from Damovisa's answer.
$(document).resize(function(){
$('#sidebar').height($('#container').height());
});
However, this could fire an awful lot if you resize the page a lot. You could try this
$(document).resize(function(){
clearTimeout(resizeTimeout);
resizeTimeout = setTimeout(function() {
$('#sidebar').height($('#container').height());
}, 100);
});
In the second example, it will only resize 100 microseconds after resizing.
This is also assuming that $(document).resize() will be triggered when the page size changes. You could always wrap it in a function, and call it on completion of any slideDown() etc

Categories

Resources