-
Notifications
You must be signed in to change notification settings - Fork 715
[resize-observer] Browsers trigger on initial observe of disconnected element, contrary to spec #11280
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Labels
Closed as Question Answered
Used when the issue is more of a question than a problem, and it's been answered.
resize-observer-1
Comments
joliss
added a commit
to joliss/lit
that referenced
this issue
Nov 28, 2024
…it#4831 The `ResizeController` would previously manually trigger an initial callback (which would get skipped if `skipInitial` is true), but this isn't necessary, as the browser's `ResizeObserver` already triggers the callback when observing initially[1]. So this commit rewrites the logic to instead suppress the initial time the `ResizeObserver` fires for a given element if `skipInitial` is true. Further improvements: - When `controller.observe(el)` is called while disconnected, we don't immediately call `observer.observe(el)` , as this would cause a duplicate `.observe` call when reconnecting. - The test suite would previously pass despite `skipInitial` not working properly. We add `await resizeComplete()` in a few places to wait two animation frames, so that we now test the behavior properly. I considered whether `skipInitial` should just be removed altogether, but I think it's actually useful for Lit specifically: Without `skipInitial`, you'll often get an extraneous `updated()` lifecycle callback after the initial component render, as the `ResizeObserver` only triggers *after* the component has already been rendered. This behavior isn't very useful, and so `skipInitial` can help avoid the performance impact of this. [1] Minor aside: According to the spec, this initial callback should only happen if the observed element is connected to the DOM. However, current browser implementations seem to trigger the callback [regardless](w3c/csswg-drafts#11280). This distinction likely isn't important for `ResizeController`'s production code, as we only observe while the host component is connected. However, I took care to avoid relying on this behavior in the test suite, in case browsers change it to conform to the spec down the line.
joliss
added a commit
to joliss/lit
that referenced
this issue
Nov 28, 2024
…it#4831 The `ResizeController` would previously manually trigger an initial callback (which would get skipped if `skipInitial` is true), but this isn't necessary, as the browser's `ResizeObserver` already triggers the callback when observing initially[1]. So this commit rewrites the logic to instead suppress the initial time the `ResizeObserver` fires for a given element if `skipInitial` is true. Further improvements: - When `controller.observe(el)` is called while disconnected, we don't immediately call `observer.observe(el)` , as this would cause a duplicate `.observe` call when reconnecting. - The test suite would previously pass despite `skipInitial` not working properly. We add `await resizeComplete()` in a few places to wait two animation frames, so that we now test the behavior properly. I considered whether `skipInitial` should just be removed altogether, but I think it's actually useful for Lit specifically: Without `skipInitial`, you'll often get an extraneous `updated()` lifecycle callback after the initial component render, as the `ResizeObserver` only triggers *after* the component has already been rendered. This behavior isn't very useful, and so `skipInitial` can help avoid the performance impact of this. [1] Minor aside: According to the spec, this initial callback should only happen if the observed element is connected to the DOM. However, current browser implementations seem to trigger the callback [regardless](w3c/csswg-drafts#11280). This distinction likely isn't important for `ResizeController`'s production code, as we only observe while the host component is connected. However, I took care to avoid relying on this behavior in the test suite, in case browsers change it to conform to the spec down the line.
See resolution in #3664 (comment) #7808 is discussing some details |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Labels
Closed as Question Answered
Used when the issue is more of a question than a problem, and it's been answered.
resize-observer-1
Uh oh!
There was an error while loading. Please reload this page.
There seems to be disagreement between the resize-observer spec and browser implementations as to whether observing a disconnected element should trigger an immediate callback, as in the following code:
Behavior according to resize-observer spec
The resize-observer chapter § 1. Introduction lists the following among the "interesting facts":
The rest of the spec does seem to agree with this conclusion: Section § 3.1. ResizeObservation example struct says that
lastReportedSizes
is initialized to[(0,0)]
, and theisActive()
function compares the element'scurrentSize
(which is itscomputedSize
) to that. But thecomputedSize
of a disconnected element should be0,0
, and thusisActive()
should be false.So my reading is that the observer should not immediately fire, because the element isn't being rendered yet.
Current browser behavior
Running the code above, Chrome, Firefox and Safari all do immediately fire, printing
where the box sizes in the
ResizeObserverEntry
array are indeed all0,0
.Suggested resolution
I'm not sure whether the browser behavior should be changed, or the spec should be brought in line with browsers' actual behavior.
The text was updated successfully, but these errors were encountered: