marcj / css-element-queries

CSS Element-Queries aka Container Queries. High-speed element dimension/media queries in valid css.
http://marcj.github.io/css-element-queries/
MIT License
4.27k stars 487 forks source link

Resize Sensor detaches when moved in DOM #171

Closed cheryllaird closed 6 years ago

cheryllaird commented 7 years ago

I need to temporarily move an element in the DOM, which has the ResizeSensor applied to it. I have found that when I do this, the ResizeSensor no longer works after the move.

I am not cloning the DOM at all, just simply moving it, so I would expect event listeners to still work. Any ideas on why the ResizeSensor is detaching?

Please see codepen for an example: https://codepen.io/cheryllaird/pen/qmJogK

marcj commented 7 years ago

My observation: That's because by moving an element, Chrome browser (only tested Chrome) resets the scrollLeft and scrollTop of all children elements without sending us the scroll event. To make the resize event working we need to reset the values of those two properties back to a value > 0 as seen in https://github.com/marcj/css-element-queries/blob/a90832ef68b7415aa85d747e4d679c9e6bdaa668/src/ResizeSensor.js#L156-L160.

Can you confirm this behaviour in your case? (that scrollLeft properties are all 0 and onScroll hasn't been fired in https://github.com/marcj/css-element-queries/blob/a90832ef68b7415aa85d747e4d679c9e6bdaa668/src/ResizeSensor.js#L178)

Two ways of fixing this:

  1. We provide an API for such cases: ResizeSensor.reset(element)
  2. We try to automate it by listening to domMutation events (which are not supported by all browsers - not sure about the coverage)

Best way is probably to implement both, although I would prefer to make an on/off switch for the second due its performance penalties:

https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Mutation_events:

Adding DOM mutation listeners to a document profoundly degrades the performance of further DOM modifications to that document (making them 1.5 - 7 times slower!). Moreover, removing the listeners does not reverse the damage.

gevgeny commented 7 years ago

@marcj @cheryllaird imho it would be great to have ResizeSensor.reset(element) or even resizeSensorInstance.reset() because atm i have to recreate ResizeSensor

gevgeny commented 7 years ago

as a temp solution based on the sources:

const expand = element.querySelector('.resize-sensor-expand');
const shrink = element.querySelector('.resize-sensor-shrink');
const expandChild = expand.childNodes[0];

expandChild.style.width = '100000px';
expandChild.style.height = '100000px';

expand.scrollLeft = 100000;
expand.scrollTop = 100000;

shrink.scrollLeft = 100000;
shrink.scrollTop = 100000;
marcj commented 6 years ago

We added ResizeSensor.reset(element) and var sensor = new ResizeSensor(element); sensor.reset() as methods in next release 1.0.0.