While working on MediaFaker, an experimental idea for displaying the effects of media queries inside any DOM node without the use of iframes, I needed a method of detecting when an element changes size. My initial thoughts lead me to a pretty naive solution involving requestAnimationFrame.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
For a rough prototype this method worked but I knew that this would not scale well when watching many elements. This method could be optimised to remove additional requestAnimationFrame calls when watching more than one element but it would still be making calls to getBoundingClientRect each frame which is on the naughty list of things to avoid causing layout / reflow. As you can see from one of my tests with 50 elements there is a lot of work being done 60 times a second.
What I wanted was a method that wouldn’t require the use of
getBoundingClientRect. So I did what all good developers would do,
I thought long and hard about the problem and used my extensive domain knowledge to come up with a solution that’s simple and elegant. I googled it. I found an extremely interesting approach by Marc J. Schmidt in his CSS-Element-Queries polyfill. The ResizeSensor module uses only native scroll events to detect when an element changes size, How I thought?
The method that the ResizeSensor uses works by adding hidden children to the element.
1 2 3 4 5 6 7 8
These elements consist of a containing div, positioned absolutely covering the entire parent element. As well as a child element that is also positioned absolutely however this child has its height and width set to 10000px making its huge.
How does this help us determine if an element has changed size though? The massive child element overflows its parent causing the parent to have scrollbars, these are hidden with overflow auto.
scrollTop properties) to 10000 effectively scrolling all the way to the end. The actual scroll offset set wont actually be 10000 though because the maximum scroll offset is
10000px - elementSize = maximum scroll offset. Noticing this formular can tell what will happen when the element changes size.
When the element changes size so does the scroll offset because we are already at the maximum, which in turn triggers an onScroll event!