PSA: New JS helpers to query layout state without forcing reflow

J. Ryan Stinnett jryans at
Wed Aug 2 19:16:37 UTC 2017

Might be useful to list somewhere on the frontend practices page,
especially so these caveats are captured.

- Ryan

On Wed, Aug 2, 2017 at 2:11 PM, Kris Maglione <kmaglione at> wrote:

> In bug 1383367, I landed a set of new helpers to make it possible to query
> the layout state (e.g., element size and position, or computed style such
> as color) without forcing an uninterruptible reflow.
> Note: Please read on for caveats before jumping into using this.
> The one that you probably really care about is promiseLayoutFlushed[1],
> which is in a lot of ways the converse of (and complement to)
> requestAnimationFrame. Its use looks something like this:
>    let width = await BrowserUtils.promiseLayoutFlushed(document,
> "layout", () => {
>      return elem.clientWidth;
>    });
>    requestAnimationFrame(() => {
> = `${width - 2*borderWidth}px`;
>    });
> This will cause the layout width of an element to be queried as soon as
> that's possible without a reflow (which may be immediately, or just after
> some other code queries the layout state, or just after the next paint),
> and then uses that width to update the DOM in the next animation frame.
> Essentially, as long as your `promiseLayoutFlushed` callback queries the
> layout *but never alters the DOM*, and your requestAnimationFrame callbacks
> alter the DOM *but never query the layout*, all queries and updates should
> happen in groups, and we shouldn't have any uninterruptible reflows. In
> theory, either of these things on their own should be enough to guarantee
> that, but in practice, we have a lot of legacy code that doesn't follow
> those rules, so this is another tool in our toolbox to get us close to that
> ideal.
> Important caveats: *Please* be careful how you use this. And especially
> keep in mind that there may need to be a paint before your promise resolves
> and any dependent DOM updates happen. If you're not absolutely sure that
> that won't result in glitchy UI behavior, *please test carefully* to make
> sure that it doesn't.
> At the moment, the implementation is fairly crude, and any callbacks which
> need to be deferred happen after the next full reflow, even if a full
> reflow isn't required. And there's no way to force deferred callbacks to be
> handled before the next paint aside from forcing a layout flush. It should
> be possible in the future, though, to schedule an interruptible reflow just
> before the next animation frame in cases where we know that's required, and
> trigger our deferred callbacks before paint. If you have a particular need
> for that, please let me know and I may be able to make it a higher priority.
> [1]:
> f0ff8f4631783b8a0e075a82/toolkit/modules/BrowserUtils.jsm#702-729
> _______________________________________________
> firefox-dev mailing list
> firefox-dev at
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <>

More information about the firefox-dev mailing list