I have a library that build UI using Javascript, and because of the dynamic content involved I sometimes want to put content out to the browser, examine how the layout was changed to support this and then do a different logic depending on the result. For example: detect if some text is overflowing and truncate it with an ellipsis.
Usually I implement this by putting out the changes, then using window.setTimeout(0) to wait for the layout to update and invoke the rest of the logic. This is obviously sub-optimal as different browsers may either implement a minimal timeout that is too slow to prevent flicker or faster that uses a lot of CPU.
Ideally I would like to do the DOM changes, then force the layout to update synchronously and run the "fix-up" logic immediately inline. Any ideas?
My understanding is that reading any of the CSS properties will force a reflow. You should not need to
setTimeout
at all.Excerpt from Rendering: repaint, reflow/relayout, restyle:
Here's a list of the API calls/properties that will trigger a reflow.
We encountered a crazy problem with IE8 (Firefox, Chrome are fine). We use toggleClass('enoMyAddressesHide') on child element.
But the parent(s) div container does not refresh/re-layout its height.
setTimeout(), read position, read width and height of element do not help. Finally we can find out a working solution:
It looks stupid, but it works!
Yes, you can!!
Most browsers optimize the reflow process by queuing changes and performing them in batches. Flushing the render tree changes requires you to retrieve some layout information ( offset calculations, getComputedStyle(), and scroll values ).
The above code will force the browser to execute changes in rendering queue in order to return the correct values.
Simple!!
I have no idea that this will actually work for your implementation, but:
I believe that setting innerHTML forces a DOM reload for a child element. I have no idea what would happen if you scoped this to the whole site. It sounds like you're pretty well hooked into the DOM all over the place though, and this method might force any node references you've already made to become undefined. In other words:
In the above instance, I believe you'll lose your reference to mySelect. If you've got lots of this going on and you're using fields not getters (i.e., not getting each element you care about using $() or $get or document.getElementById(..) every time you access it) then there's a strong chance this type of flushing could hose you.
You'd also most certainly lose any page state data you're not manually tracking/setting - textboxes with new text from the user, checkboxes newly checked by the user, etc, would reinitialize to their default state using this approach to flushing.
Good luck - happy coding!
B