The clientHeight property doesn't force a reflow, at least not by itself. You need two things to trigger a reflow:
- dirty the current layout (set a layout property like width or height)
- query a layout property (clientHeight for example)
You can easily batch calls to set the width or height and no reflow will happen until the JS context relinquishes control. You can easily batch queries for layout properties and no reflow will happen if the current layout is not dirty.
The problem appears when you do 1 and 2 in succession. The reflow is forced in order to satisfy your query with accurate information.
To my knowledge you are correct that having an absolutely positioned ancestor should limit the reflow from "spreading" all over the document (the parent of the absolutely positioned ancestor will not reflow). All the items inside the absolutely positioned ancestor will still reflow!
As for a solution to your problem yes there is. Set a caching mechanism, like this (pseudocode):
forEachDiv(function(div) {
div.getClientHeight = function(){
return div.cachedClientHeight = div.cachedClientHeight || div.clientHeight;
}
});
You can then use div.getClientHeight()
instead of div.clientHeight
as many times as you want and only the first usage will trigger a reflow (if dirty).
Obviously, keeping in line with the first suggestion, you can also artificially query the clientHeight for all the divs in one batch ( = one reflow) and you have no more problems afterwards.
// cache the client height for all divs now, to avoid reflows later
forEachDiv(function(div) {
div.getClientHeight();
});