Detect Document Height Change
Update (Oct 2020):
resizeObserver is a wonderful API (support table)
// create an Observer instance
const resizeObserver = new ResizeObserver(entries =>
console.log('Body height changed:', entries[0].target.clientHeight)
)
// start observing a DOM node
resizeObserver.observe(document.body)
// click anywhere to rnadomize height
window.addEventListener('click', () =>
document.body.style.height = Math.floor((Math.random() * 5000) + 1) + 'px'
)
click anywhere to change the height
Old answer:
Although a "hack", this simple function continuously "listens" (through setTimeout) to changes in an element's height and fire a callback when a change was detected.
It's important to take into account an element's height might change regardless of any action taken by a user (resize, click, etc.) and so, since it is impossible to know what can cause a height change, all that can be done to absolutely guarantee 100% detection is to place an interval height checker :
function onElementHeightChange(elm, callback) {
var lastHeight = elm.clientHeight, newHeight;
(function run() {
newHeight = elm.clientHeight;
if (lastHeight != newHeight)
callback(newHeight)
lastHeight = newHeight
if (elm.onElementHeightChangeTimer)
clearTimeout(elm.onElementHeightChangeTimer)
elm.onElementHeightChangeTimer = setTimeout(run, 200)
})()
}
// to clear the timer use:
// clearTimeout(document.body.onElementHeightChangeTimer);
// DEMO:
document.write("click anywhere to change the height")
onElementHeightChange(document.body, function(h) {
console.log('Body height changed:', h)
})
window.addEventListener('click', function() {
document.body.style.height = Math.floor((Math.random() * 5000) + 1) + 'px'
})
You can use an absolute
positioned iframe
with zero width inside the element you want to monitor for height changes, and listen to resize
events on its contentWindow
. For example:
HTML
<body>
Your content...
<iframe class="height-change-listener" tabindex="-1"></iframe>
</body>
CSS
body {
position: relative;
}
.height-change-listener {
position: absolute;
top: 0;
bottom: 0;
left: 0;
height: 100%;
width: 0;
border: 0;
background-color: transparent;
}
JavaScript (using jQuery but could be adapted to pure JS)
$('.height-change-listener').each(function() {
$(this.contentWindow).resize(function() {
// Do something more useful
console.log('doc height is ' + $(document).height());
});
});
If for whatever reason you have height:100%
set on body
you'll need find (or add) another container element to implement this on. If you want to add the iframe
dynamically you'll probably need to use the <iframe>.load
event to attach the contentWindow.resize
listener. If you want this to work in IE7 as well as browsers, you'll need to add the *zoom:1
hack to the container element and also listen to the 'proprietary' resize
event on the <iframe>
element itself (which will duplicate contentWindow.resize
in IE8-10).
Here's a fiddle...
Just my two cents. If by any chance you're using angular then this would do the job:
$scope.$watch(function(){
return document.height();
},function onHeightChange(newValue, oldValue){
...
});
Update: 2020
There is now a way to accomplish this using the new ResizeObserver. This allows you to listen to a whole list of elements for when their element changes size. The basic usage is fairly simple:
const observer = new ResizeObserver(entries => {
for (const entry of entries) {
// each entry is an instance of ResizeObserverEntry
console.log(entry.contentRect.height)
}
})
observer.observe(document.querySelector('body'))
The one downside is that currently there is only support for Chrome/Firefox, but you can find some solid polyfills out there. Here's a codepen example I wrote up:
https://codepen.io/justin-schroeder/pen/poJjGJQ?editors=1111