Skip to content
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

Should the contents of display:none iframes really be considered as "being rendered"? #1813

Open
bzbarsky opened this issue Sep 23, 2016 · 13 comments · Fixed by #1859
Open

Comments

@bzbarsky
Copy link
Contributor

A literal reading of the specs seems to say that a display:none iframe behaves in the following way:

  1. It creates a viewport sized 0x0.
  2. It then proceeds to do layout inside that viewport.

Claim 1 is supported by https://html.spec.whatwg.org/multipage/rendering.html#the-page:document kinda. There is no actual definition of what "being rendered" means for a browsing context, but I expect that it should be defined to mean the same thing as "being rendered" means for the browsing context container. Or something. This needs to be tightened up in the spec.

Claim 2 is supported by the fact that none of the mentions of "being rendered" in HTML say the stuff inside the subframe is not "being rendered". Note that this means that focusing things in that display:none iframe should work, per spec, and so forth.

I believe item 2 is a clear spec bug. Certainly allowing focusing things in display:none iframes (but not display:none things directly!) seems like a spec bug to me, and forcing UAs to do likely-expensive layout on the contents of display:none iframes seems weird.

It would be ideal if HTML and CSS could sort out this behavior between the two of them.

In terms of actual UA behavior, it looks like WebKit and Blink do in fact allow focusing things inside a display:none iframe [1]. Edge and Gecko do not. Gecko and Edge also do not perform box construction or layout inside display:none iframes [2].

It seems to me that the fast and sane thing of considering everything inside a display:none iframe as "not being rendered" is web compatible enough (given that this is what Edge and Gecko ship), that we should really consider speccing it.

[1] Testcase:

<iframe style="display: none" src="subframe.html"></iframe>
<script>
  onload = function() {
    frames[0].document.querySelector("input").focus();
    alert(document.activeElement);
    alert(frames[0].document.activeElement);
  }
</script>

where subframe.html contains a single <input> tag.

[2] Testcase:

<iframe style="display: none" src="subframe.html"></iframe>
<script>
  onload = function() {
    var win = frames[0];
    var s = win.getComputedStyle(win.document.querySelector("div"));
    alert(s.height);
 }
</script>

where subframe.html has <div>Hey</div>: this alerts "auto" in Edge.

/cc @annevk @tabatkins

@annevk
Copy link
Member

annevk commented Sep 26, 2016

So the main question here is whether WebKit and Blink (paging @smfr and @esprehn) are interested in optimizing display:none <iframe>s by not creating boxes for elements in such <iframe>s' documents.

@domenic
Copy link
Member

domenic commented Sep 26, 2016

I hear @zetafunction also knows things about Blink iframes. Daniel, do you think Blink is interested in optimizing display:none <iframe>s by not creating boxes for elements in such <iframe>s' documents, like Gecko and Edge do?

I tend to agree with @bzbarsky that given the 2/2 split, we should spec the more reasonable behavior of not creating such boxes. But it would be nice to get some opinions first.

@esprehn
Copy link

esprehn commented Sep 26, 2016

I support this change though I do worry it'll break some content. We'll have to try it.

@smfr
Copy link

smfr commented Sep 26, 2016

Ditto for WebKit. I filed https://bugs.webkit.org/show_bug.cgi?id=162560

@esprehn
Copy link

esprehn commented Sep 26, 2016

@domenic
Copy link
Member

domenic commented Oct 4, 2016

So I guess we should fix this in the spec by specifying somewhere that no CSS layout boxes are created for elements inside iframes that are not themselves being rendered. That is, changing the definition of "has CSS layout boxes" seems better than changing the definition of "being rendered".

I assume that will require CSS spec changes? @zcorpan, could you help us out here?

I'll submit a PR for the cleanup @bzbarsky mentions in the OP.

domenic added a commit that referenced this issue Oct 4, 2016
Instead of talking about a browsing context being rendered, talk about its container. Fixes part of #1813.
@bzbarsky
Copy link
Contributor Author

bzbarsky commented Oct 4, 2016

That is, changing the definition of "has CSS layout boxes" seems better than changing the definition of "being rendered"

Yes, I agree.

@zcorpan
Copy link
Member

zcorpan commented Oct 5, 2016

Filed w3c/csswg-drafts#571 for the CSS side

annevk pushed a commit that referenced this issue Oct 5, 2016
Instead of talking about a browsing context being rendered, talk about its container. Fixes part of #1813.
@annevk annevk reopened this Oct 5, 2016
MXEBot pushed a commit to mirror/chromium that referenced this issue Feb 16, 2017
Most of this CL is plumbing for FrameOwnerProperties. Interesting changes:
  * LayoutView can no longer have children if its FrameOwner is "DisplayNone".
  * A local frame is "DisplayNone" if and only if it has no widget [which should
    correspond to the actual display:none style].
  * The DisplayNone property is propagated to remote frames via
    FrameOwnerProperties.

Spec discussion: whatwg/html#1813

BUG=650433
CQ_INCLUDE_TRYBOTS=master.tryserver.chromium.linux:linux_site_isolation

Review-Url: https://codereview.chromium.org/2564633002
Cr-Commit-Position: refs/heads/master@{#450748}
jeffcarp pushed a commit to web-platform-tests/wpt that referenced this issue Feb 16, 2017
Most of this CL is plumbing for FrameOwnerProperties. Interesting changes:
  * LayoutView can no longer have children if its FrameOwner is "DisplayNone".
  * A local frame is "DisplayNone" if and only if it has no widget [which should
    correspond to the actual display:none style].
  * The DisplayNone property is propagated to remote frames via
    FrameOwnerProperties.

Spec discussion: whatwg/html#1813

BUG=650433
CQ_INCLUDE_TRYBOTS=master.tryserver.chromium.linux:linux_site_isolation

Review-Url: https://codereview.chromium.org/2564633002
Cr-Commit-Position: refs/heads/master@{#450748}
jeffcarp pushed a commit to web-platform-tests/wpt that referenced this issue Feb 16, 2017
…rames. (patchset #31 id:650001 of https://codereview.chromium.org/2564633002/ )

Reason for revert:
Suspect for webkit_tests leak failures (https://crbug.com/692872).

See bug for details.

Original issue's description:
> Don't create layout objects for children of display-none iframes.
>
> Most of this CL is plumbing for FrameOwnerProperties. Interesting changes:
>   * LayoutView can no longer have children if its FrameOwner is "DisplayNone".
>   * A local frame is "DisplayNone" if and only if it has no widget [which should
>     correspond to the actual display:none style].
>   * The DisplayNone property is propagated to remote frames via
>     FrameOwnerProperties.
>
> Spec discussion: whatwg/html#1813
>
> BUG=650433
> CQ_INCLUDE_TRYBOTS=master.tryserver.chromium.linux:linux_site_isolation
>
> Review-Url: https://codereview.chromium.org/2564633002
> Cr-Commit-Position: refs/heads/master@{#450748}
> Committed: https://chromium.googlesource.com/chromium/src/+/962434d34e2c9bcd17488f499515920c298b5395

TBR=esprehn@chromium.org,dcheng@chromium.org,avi@chromium.org,erikchen@chromium.org
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=650433

Review-Url: https://codereview.chromium.org/2696283003
Cr-Commit-Position: refs/heads/master@{#450855}
MXEBot pushed a commit to mirror/chromium that referenced this issue Feb 17, 2017
…rames. (patchset #31 id:650001 of https://codereview.chromium.org/2564633002/ )

Reason for revert:
Suspect for webkit_tests leak failures (https://crbug.com/692872).

See bug for details.

Original issue's description:
> Don't create layout objects for children of display-none iframes.
>
> Most of this CL is plumbing for FrameOwnerProperties. Interesting changes:
>   * LayoutView can no longer have children if its FrameOwner is "DisplayNone".
>   * A local frame is "DisplayNone" if and only if it has no widget [which should
>     correspond to the actual display:none style].
>   * The DisplayNone property is propagated to remote frames via
>     FrameOwnerProperties.
>
> Spec discussion: whatwg/html#1813
>
> BUG=650433
> CQ_INCLUDE_TRYBOTS=master.tryserver.chromium.linux:linux_site_isolation
>
> Review-Url: https://codereview.chromium.org/2564633002
> Cr-Commit-Position: refs/heads/master@{#450748}
> Committed: https://chromium.googlesource.com/chromium/src/+/962434d34e2c9bcd17488f499515920c298b5395

TBR=esprehn@chromium.org,dcheng@chromium.org,avi@chromium.org,erikchen@chromium.org
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=650433

Review-Url: https://codereview.chromium.org/2696283003
Cr-Commit-Position: refs/heads/master@{#450855}
jeffcarp pushed a commit to web-platform-tests/wpt that referenced this issue Mar 30, 2017
…iframes.

The initial CL leaked DOM objects by calling
documentElement()->lazyReattachIfAttached() during Document::shutdown(). This
reland advances m_lifecycle to DocumentLifecycle::Stopping slightly earlier in
Document::shutdown(), and then only triggers
documentElement()->lazyReattachIfAttached() if the state is earlier than
DocumentLifecycle::Stopping.

Partial stack of the DOM leak:
  ...
  documentElement()->lazyReattachIfAttached();
  blink::Document::willChangeFrameOwnerProperties()\n
  blink::HTMLFrameOwnerElement::setWidget()\n
  blink::FrameView::dispose()\n
  blink::Document::shutdown()\n
  blink::FrameLoader::prepareForCommit()\n
  blink::FrameLoader::commitProvisionalLoad()\n
  blink::DocumentLoader::commitIfReady()\n
  blink::DocumentLoader::processData()

> Most of this CL is plumbing for FrameOwnerProperties. Interesting changes:
>   * LayoutView can no longer have children if its FrameOwner is "DisplayNone".
>   * A local frame is "DisplayNone" if and only if it has no widget [which should
>     correspond to the actual display:none style].
>   * The DisplayNone property is propagated to remote frames via
>     FrameOwnerProperties.
>
> Spec discussion: whatwg/html#1813

BUG=650433

Review-Url: https://codereview.chromium.org/2743053003
Cr-Commit-Position: refs/heads/master@{#460646}
MXEBot pushed a commit to mirror/chromium that referenced this issue Mar 31, 2017
…f display-none iframes.

The initial CL leaked DOM objects by calling
documentElement()->lazyReattachIfAttached() during Document::shutdown(). This
reland advances m_lifecycle to DocumentLifecycle::Stopping slightly earlier in
Document::shutdown(), and then only triggers
documentElement()->lazyReattachIfAttached() if the state is earlier than
DocumentLifecycle::Stopping.

Partial stack of the DOM leak:
  ...
  documentElement()->lazyReattachIfAttached();
  blink::Document::willChangeFrameOwnerProperties()\n
  blink::HTMLFrameOwnerElement::setWidget()\n
  blink::FrameView::dispose()\n
  blink::Document::shutdown()\n
  blink::FrameLoader::prepareForCommit()\n
  blink::FrameLoader::commitProvisionalLoad()\n
  blink::DocumentLoader::commitIfReady()\n
  blink::DocumentLoader::processData()

> Most of this CL is plumbing for FrameOwnerProperties. Interesting changes:
>   * LayoutView can no longer have children if its FrameOwner is "DisplayNone".
>   * A local frame is "DisplayNone" if and only if it has no widget [which should
>     correspond to the actual display:none style].
>   * The DisplayNone property is propagated to remote frames via
>     FrameOwnerProperties.
>
> Spec discussion: whatwg/html#1813

BUG=650433

Review-Url: https://codereview.chromium.org/2743053003
Cr-Commit-Position: refs/heads/master@{#460646}
nle-odoo added a commit to odoo-dev/odoo that referenced this issue Jan 30, 2018
It seems that firefox has some difference of behavior from other
browsers as said in:

- https://bugzilla.mozilla.org/show_bug.cgi?id=548397
- whatwg/html#1813
- w3c/csswg-drafts#571

It seems that at least in one instance (a html field hidden on the pos
configuration), firefox fails because of something similar:
window.getComputedStyle(element) returns `null` instead of the element
styles.

In my tests, using the parent window (possible if current frame and
parent have the same origin which should be the case) worked in this
instance, this is examplified by this jsfiddle:
 https://jsfiddle.net/Lpv898ve/2/

This work with window.parent and not using window directly.

So this commit adds fallback on doing getComputedStyle from the parent
window (when testing on chromium this gave exactly the same result that
before).

opw-813363
fixes odoo#22211
closes odoo#22610
@erikchen
Copy link

When we implemented this in Blink we discovered that there's a fairly common pattern among web developers to call Window.print() on display:none iframes. We updated our implementation to allow layout of display:none iframes during a call to Window.print(), which appears to match the behavior of other JS implementations. Should we update the spec to include this caveat?

@chrishtr
Copy link
Contributor

Also, the Window.print functionality exists in both Firefox and Safari, so there does appear to be
a de facto standards quirk in this situation.

@bzbarsky
Copy link
Contributor Author

Note that print(), in Firefox, creates an immutable clone of the document and prints it asynchronously. It does not lay out the actual document involved in any sort of print mode, so it's not a quirk in that sense: the thing being laid out is not the thing in the display:none iframe at all.

Yes, this is quite different from the behavior of Blink, which messes with the actual being-shown document. Of course the spec for print() is fairly handwavy....

alice pushed a commit to alice/html that referenced this issue Jan 8, 2019
Instead of talking about a browsing context being rendered, talk about its container. Fixes part of whatwg#1813.
@andreasonny83
Copy link

Short answer YES. In my opinion, the content of a display:none iframe should always render.
Here's why and it's very simple.

An iframe is basically like a browser inside another browser and it allows developers to display contents coming from the outside WWW, so it's basically like a window into another dimension.
Given that the previous assumption is correct, then the fact that that window is hidden, should not, in any way, alter the functionality of the targetted dimension. If this cannot be guaranteed then there will be unpredictable consequences on the targetted website.
If, for instance, a website is doing some rendering in the background based on some HTML element dimensions, then the result of that calculation will be compromised by the fact that the website is rendered inside a hidden iframe which is only fine as long as the iframe is not visible. But, when the user toggles that visibility, then the rendered content in the iframe will be useless because compromised by external factors not in control by the targetted website.
Starting from Chrome v74 this bug can be easily reproduced as I reported on this bug https://bugs.chromium.org/p/chromium/issues/detail?id=963876. However, the Chromium team doesn't consider this as a bug

@chrishtr
Copy link
Contributor

The problem is that the size of an iframe, whether it renders anything, and even when it renders,
is controlled by its parent. Also, your proposal has serious performance implications. It's really important not to do unnecessary rendering work.

@zcorpan zcorpan removed their assignment Sep 9, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging a pull request may close this issue.

9 participants