I have a function that positions an element in my Firefox extension, and I need that function to be called whenever an event causes the window/chrome layout to change.
Events would be:
When a new window is created, after the chrome is rendered.*
When a window is re-sized.
Any other event that might cause the chrome layout to change size or shape?
(*) Right now, the function runs when a new window is created using:
window.addEventListener("load",myfunction);
But this runs before the chrome is rendered, and element sizes have wonky values. I need it to run after Firefox determines the actual size and placement of the chrome elements.
What are the events I would need to bind to, and how do I bind them?
I was in a similar situation, and didn't really find a good solution. However, the non-standard MozAfterPaint event may help, but comes with a somewhat sizable performance penalty however (so make sure you remove it once you don't need it anymore).
The resize event should do the trick.
There are tons of things that may cause things to change. New CSS/Images loading, toolbar customization, etc. 1. and 2. should cover most (all?), however.
The devtools layoutview ("Box Model") seems to use MozAfterPaint as well.
If possible, you should try to avoid having to calculate sizes yourself, however, by making use of the XUL/HTML flexbox model and CSS without fixed sizes (or min/max sizes only).
Related
I'm working on some code I inherited that uses jQuery to generate some DIV blocks containing text and images. It generates the blocks, appends them to the page, then calls outerHeight() on the blocks' inner text elements and uses those heights to calculate how big the accompanying images should be.
In all browsers except Safari, things work fine.
In Safari, when outerHeight() is called, sometimes the just-appended elements aren't fully rendered, so the measurement returned is not accurate, and the resulting page doesn't look right. I can see this in the debugger - my breakpoint is hit just after an incorrect outerHeight() is saved, after a second or two I see the rendering catch up, and calling outerHeight() again gives the correct value.
I've tried to serialize this sequence more explicitly using setTimeout and to call outerHeight() a bit later in the code. This made the issue happen less frequently, but it still happens sometimes.
I feel like this has to be a common pattern - get the dimensions of just-appended elements. Has anyone dealt with this before?
Experimenting with various delays, I saw that most of the time, Safari would finish rendering the appended elements after no more than 250ms or so. To deal with this issue, I use setTimeout to run a function after a delay to check whether the previously measured heights match the current ones in the DOM. If they don't, then I know that the rendering has changed, and I re-do the layout of these elements.
For a long time, I've been looking for a way to detect when a DOM element's size or position has changed. It could be because the window resized, or because new child elements were added to the element, or because new elements were added around this element, or because CSS rules have changed, or because the user has changed their browser's font size. There are a huge number of reasons that an element's size or position would change.
I could hook event handlers for many of those events, but I think there are cases that aren't covered. I had hoped to use MutationObservers to just watch the element's offsetWidth or clientWidth, but it looks like those only apply to DOM attributes, not Node properties (or maybe that's just what Webkit implements). So, to be truly bulletproof, it looks like I would need to run a polling loop anyway.
Is this correct? Have I missed something important? Is polling the only bulletproof way to detect when an element's size or position has changed?
Edit
To give a little more context, this isn't tied to any one particular use case. For me, it has come up time and time again. In my current situation, I was hoping to have a canvas that is set, via CSS, to be 100% width and height of its parent. I want a script to adjust the canvas's width and height properties when its offsetWidth or clientWidth changed (this is for WebGL, where the width and height properties affect the framebuffer resolution). In another project, I wanted to have an element expand in height to fill whatever remaining space was in the user's browser window. I have come across this situation time and time again and, inevitably, the solution seems to be:
Listen to window.resize
Hook into any code that you write that might change the DOM (or maybe use Mutation Events or Mutation Observers)
Have a periodic polling operation to clean up any missed cases
(most people stop at 1, and maybe do a little of 2)
I just wanted to make sure I wasn't missing something vital.
Incidentally, in my WebGL situation, listening to window.resize is sufficient (and is somewhat preferable, because then the canvas dimensions and rendering resolution change at the same time).
You might could do it with CSS animations. Check out http://developer.streak.com/2012/11/how-to-detect-dom-changes-in-css.html and similar. I suppose it won't handle all your requirements though, now that I read through it some more.
A co-worker pointed me to a technique that uses the underflow and overflow events. I haven't tried it, and I have no idea what kind of browser support there is (looks like Chrome and FireFox, and it should work in IE by synthesizing the same events that browser would look for, but I have no idea which versions support the technique).
As of 2019, you have access to:
ResizeObserver to fire callback on size change. Be careful here, it's not supported everywhere yet.
MutationObserver that could be used for position, but I guess that's a bit overkill. Well supported though.
IntersectionObserver as a bonus, that allows you to check for intersection with ancestors. Extremly useful to optimize stuff, especially in WebGL. This is pretty well supported.
Our site uses Websocket, so it already requires late-model browsers. Given that, how can I be notified when an element resizes? We may have canvas and svg child elements that need to resize in response to the parent DOM element resizing.
Elegant method would be to hook 'onresize' but, alas, it does not get called on elements (at least not in Chrome 18). Would prefer to not be offered an answer to periodically fire a timer to test for a change in element size.
Also, please understand that the reflow may not be caused by the window or body being resized, so please don't go there.
Any brilliant, simple, elegant ideas would be hugely appreciated.
How I can capture browser restore/maximize event in jQuery or javascript? We can use window.onresize but that only tells that the browser is resized. thanks!
There is no way to determine this on script level.
You could - as a very unreliable workaround - compare the window.width and document.clientWidth properties after a resize event and see whether they match, or almost match. If they do, it's possible a maximize action has taken place.
I think it won't get any better than that, and even this method is subject to many, many factors. If there is a vertical toolbar, preventing the browser from resizing to the screen's full width, the values will differ, making it harder and harder to determine a resize event.
On a dynamic site of mine I faced a problem that consists in the following:
In Internet Explorer 6 after changing the size of the div element with the help of JavaScript, its child elements that are 100% in height do not refresh right away (ie. do not stretch to their new size) but only when the parent div is clicked. It seems to me that the document needs some update. I'd like to ask if there is sort of a command (like that in Flash) that updates the document after some dynamic changes get happened? In brief, how can this problem be settled?
Requiring reflow in IE6 is a very common problem with a massive CSS/JS base. Usually all you have to do is change a parameter on the element that requires a reflow, like, for example, set display:none and then back. This will cause browser to reflow objects in and around current object. Most of the time you will have to do it from JavaScript. If you don't want to do display, try changing height/width or add/remove flow or clear parameters. They all will cause reflows of the page.
However, most of the time if you are running into reflow issues in IE6 it usually means that either you have way too much CSS on the page, or you are using CSS for things it shouldn't be used for (like laying out elements on the page that in HTML go in a wrong order, i.e. element1, element2, element3 in HTML; element2, element1, element3 in display). I would suggest cleaning up your CSS and most of the times, reflow problems will go away.
If you have to click on it to refresh, then why no try to simulate a click, after the size update. Simulating mouse clicks in JavaScript
I know that I have been burned (more than once unfortunately) to have returned invalid xml for an ajax response. IE in particular is very non-forgiving in this respect. It might be worth validating the response just to be sure. In some of my cases, the bad XML caused JS to fail and not "seem to work".