Last Comment Bug 548397 - window.getComputedStyle() returns null inside an iframe with display: none
: window.getComputedStyle() returns null inside an iframe with display: none
Status: NEW
:
Product: Core
Classification: Components
Component: DOM: CSS Object Model (show other bugs)
: unspecified
: x86 Linux
-- normal with 19 votes (vote)
: ---
Assigned To: Nobody; OK to take it and work on it
:
: Jet Villegas (:jet)
Mentors:
http://ministeyr.free.fr/testcases/gc...
: 1079486 (view as bug list)
Depends on: 1308675
Blocks: 974529 1302780
  Show dependency treegraph
 
Reported: 2010-02-24 12:55 PST by Jordan Osete
Modified: 2016-10-22 18:03 PDT (History)
27 users (show)
See Also:
Crash Signature:
(edit)
QA Whiteboard:
Iteration: ---
Points: ---
Has Regression Range: ---
Has STR: ---


Attachments
Test Case (472 bytes, text/html)
2012-07-13 04:11 PDT, FredCK
no flags Details
Simple proof of concept of option 3 (8.20 KB, patch)
2016-09-01 21:18 PDT, Boris Zbarsky [:bz] (still a bit busy)
no flags Details | Diff | Splinter Review

Description User image Jordan Osete 2010-02-24 12:55:35 PST
User-Agent:       Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2) Gecko/20100115 Firefox/3.6
Build Identifier: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2) Gecko/20100115 Firefox/3.6

getComputedStyle() returns null if the page is loaded in an iframe with display: none;

Reproducible: Always

Steps to Reproduce:
1. go to http://ministeyr.free.fr/testcases/gcs2.htm

Actual Results:  
The page alerts "null"

Expected Results:  
The page should alert something like [object CSSStyleDeclaration]
It happens correctly if the page is not loaded inside an iframe (see http://ministeyr.free.fr/testcases/gcs.htm )
Comment 1 User image Boris Zbarsky [:bz] (still a bit busy) 2010-02-24 14:53:38 PST
If you're display:none then the information needed to compute style (which medium is in use, the size of the CSS viewport, the zoom level, etc) is not present.  So yes, this is the expected behavior given the current style computation implementation in Gecko.

The CSSOM spec might require a different behavior at some point, but in the meantime this is something to bring up with the relevant working group.
Comment 2 User image Jordan Osete 2010-02-28 02:11:55 PST
A simple workaround is to style the iframe with
  visibility: hidden;
  position: absolute;
Although "display: none" probably impacts performance less, but this should not be very significant.
Comment 3 User image FredCK 2012-07-13 04:11:44 PDT
Created attachment 641808 [details]
Test Case

Attached a simple test case for it. It passes on Chrome and Opera while fails with Firefox.
Comment 4 User image jonl 2013-06-13 09:52:05 PDT
@Boris,

Your statement does not make sense.  Another workaround to this issue is to provide the iframe with a fixed width and height.  If you do that, then even if the style display:none is set, getComputedStyle will not return null.
Comment 5 User image Boris Zbarsky [:bz] (still a bit busy) 2013-06-13 10:43:22 PDT
jonl, I have no idea what you're talking about.  Fixed width and height have no effect on this bug.
Comment 6 User image jonl 2013-06-13 10:51:05 PDT
I retract my comment.  I have run into this with my own application and thought I had seen different behavior with a fixed size iframe, but appear to be mistaken.
Comment 7 User image Ten 2014-01-25 13:54:30 PST
I ran into this bug with a piece of software I'm developing and found a solution to it.

In my code I was dynamically changing the src property of an iframe that was located inside a jquery ui dialog so this might be situational. I set a micro timeout 'window.setTimeout(fuction() { });' around the code that changed the 'src' property of the iframe and it works every time now without throwing this error.
Comment 8 User image Greg 2014-04-18 02:03:01 PDT
I have make a patch for my application which use jquery.mobile in an iframe.
I did not want change the behaviour of the jquery.mobile to assure the compatibilty with updates of library.
I have overload the getComputedStyle function by checking the result and replace it by an empty object in case it is null.

if (/firefox/i.test(navigator.userAgent)){
   window.oldGetComputedStyle = window .getComputedStyle;
   window.getComputedStyle = function (element, pseudoElt) {
      var t = window.oldGetComputedStyle(element, pseudoElt);
      if (t === null) {
         return {};
      } else{
         return t;
      }
   };
}
Comment 9 User image Travis Everett 2014-06-23 09:20:59 PDT
We ran into this bug while updating versions of Adobe Captivate. Captivate warns against use of browsers other than chrome/IE/Safari, but it seems whatever issues they had with FF are largely in the past.

Still, when we include a Captivate (versions 7/8, at least) in an unopened iframe until the user clicks to display the iframe in a modal, this issue crops up.

I'm not involved in the spec here enough to _know_ if it's naive of Adobe to be making assumptions (i.e., getComputedStyle(el) will return an object with top/right/bottom/left/marginTop/marginRight/marginBottom/marginLeft/width/height values) but it seems like the spec (http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSview-getComputedStyle) gives no indication that a null return value should be anticipated.
Comment 10 User image Boris Zbarsky [:bz] (still a bit busy) 2014-06-23 09:33:16 PDT
The relevant spec is http://dev.w3.org/csswg/cssom/ for what it's worth.  But yes, returning null is probably wrong, which is why this bug is open.  Fixing it requires pretty significant changes to how style computation works in Gecko, unfortunately.
Comment 11 User image Travis Everett 2014-06-23 10:10:29 PDT
Thanks for the quick update, Boris.

We used a modified version of Greg's patch above to return a dummy object with values for the necessary keys to cover our case in the near term; largely posting to document the interaction between this issue and Captivate, in case it adds some helpful weight to the case for an eventual fix.
Comment 12 User image sim 2014-07-23 11:31:19 PDT
We are seeing window.getComputedStyle() return null for DOM elements that are not inside iframes. This is happening thousands of different sites for millions of users where our scripts are running. FF only behavior; not happening on any other browser. Unfortunately, we haven't been able to isolate a self-contained test case yet. 

Still, for the purposes of considering a fix we wanted to make sure that this use case demonstrating the problem is known.
Comment 13 User image Boris Zbarsky [:bz] (still a bit busy) 2014-07-23 11:37:23 PDT
sim, I'm not aware of a way for getComputedStyle to return null unless the method is being called on a window with no presentation.  That means it's either a display:none iframe (or some iframe that has no box; e.g. a direct child of a non-foreignObject SVG element) or a tab that was somehow hidden by some extension.
Comment 14 User image sim 2014-07-23 15:01:21 PDT
(In reply to Boris Zbarsky [:bz] from comment #13)

Well, it's happening with clockwork consistency. While I cannot give you an isolated reproducible case, I'd be happy to screen share and demonstrate. 

Here is an interesting twist, which hopefully sheds some light. The DOM element being manipulated and the window reference come from the main frame of web page (not iframed) but the JavaScript calling the method on that window reference was loaded in a same-domain hidden iframe.
Comment 15 User image Boris Zbarsky [:bz] (still a bit busy) 2014-07-23 18:51:28 PDT
> but the JavaScript calling the method on that window reference was loaded in a
> same-domain hidden iframe.

What does that javascript call look like, exactly?
Comment 16 User image sim 2014-07-23 19:12:06 PDT
(In reply to Boris Zbarsky [:bz] from comment #15)

Here is the current code (with a workaround for this FF issue). We got bitten by this issue when attempting to show a hidden DOM element.

The DOM element in question is a DIV in the main frame with display: none. When window.getComputedStyle() returns null, jQuery's fadeIn() fails to make the element appear but show() does alright. 

_makeVisible: function() {
  var domNode = this.$ele.get(0);
  if (window.getComputedStyle(domNode)) {
    this.$ele.fadeIn(200);
  } else {
    this.$ele.show();
  }
}
Comment 17 User image Boris Zbarsky [:bz] (still a bit busy) 2014-07-23 19:24:18 PDT
>  if (window.getComputedStyle(domNode)) {

Is this code running in the display:none iframe?
Comment 18 User image sim 2014-07-23 19:33:55 PDT
(In reply to Boris Zbarsky [:bz] from comment #17)

Yes, the code is running in the display: none same-domain iframe. However, window references the top-level frame on the page.
Comment 19 User image Boris Zbarsky [:bz] (still a bit busy) 2014-07-23 20:07:28 PDT
"window" in that function references the window the code is running in, which you say is the display:none iframe, unless the function is closing over some scope with "var window" in it.
Comment 20 User image Hallvord R. M. Steen [:hallvors] 2014-09-05 02:54:26 PDT
http://webcompat.com/issues/300 documents how m.futureshop.ca is unusable due to this bug.
Comment 21 User image Hallvord R. M. Steen [:hallvors] 2014-09-05 03:16:10 PDT
A test for reading the display property from an element inside a display:none IFRAME (should say 'block') with jQuery: http://jsfiddle.net/zn7akfxg/
Comment 22 User image Hallvord R. M. Steen [:hallvors] 2014-10-04 06:56:21 PDT
*** Bug 1075280 has been marked as a duplicate of this bug. ***
Comment 23 User image Boris Zbarsky [:bz] (still a bit busy) 2014-10-07 15:08:47 PDT
*** Bug 1079486 has been marked as a duplicate of this bug. ***
Comment 24 User image Thayne 2015-10-16 19:48:19 PDT
If the iframe isn't displayed, couldn't getComputedStyle(node) just return a copy of node.style?
Comment 25 User image Boris Zbarsky [:bz] (still a bit busy) 2015-10-16 19:54:54 PDT
That has quite different behavior from the computed style, unfortunately.  In particular, it doesn't have values for properties that are not actually set in the inline style.
Comment 26 User image GregAmbrose 2015-12-20 19:22:20 PST
I bypassed the problem very easily with JQuery as follows.

        <div>
            <iframe id='linkIframe' width='1200px' height='300px'></iframe>
        </div>
          
          <script>

          $(document).ready(function() 
          {
    	     $("#linkIframe").attr("src", "/iadmin2/plugins/jobcard/externalMedia.php");
          });

         </script>
Comment 27 User image Benjamin Tan 2016-03-06 03:06:44 PST
Could an empty object be returned instead of null? This would fix errors as most people typically do stuff like getComputedStyles(obj).color.
Comment 28 User image Boris Zbarsky [:bz] (still a bit busy) 2016-09-01 21:07:21 PDT
So I ran into yet another site today that breaks as a result of this.

I think we have the following options at this point:

1)  Wait for stylo to land, try to fix this on top of stylo.  At that point style computation won't be quite as tied to the presshell, and we might be able to just make it work.  I'm not sure what sort of timeframe this would entail.

2)  Divorce style computation from the presshell.  That is, move the style struct arenas, style set, etc, etc over to the document.  This would take quite a bit of work in its own right...

3)  Hack something together where we return non-null (this part is easy) and either have it throw on access like happens now if you grab a computed style object and then go display:none or have it return some sort of bogus data (e.g. as suggested in comment 27).  The former option does _not_ fix the site I mention above, but the latter one does.  Just returning "" for everything is actually fairly simple to do.

David, thoughts?  Bobby, do we have any sort of firm-ish time estimate for stylo?
Comment 29 User image Boris Zbarsky [:bz] (still a bit busy) 2016-09-01 21:18:26 PDT
Created attachment 8787509 [details] [diff] [review]
Simple proof of concept of option 3
Comment 30 User image Bobby Holley (:bholley) (busy with Stylo) 2016-09-05 18:37:58 PDT
The comments in the bug don't make it entirely clear what the issue is (and which parts are expected/unexpected per-spec) - Boris, can you elaborate on that?

(I'll be slow to respond, in TPE for stylo meetup)
Comment 31 User image Boris Zbarsky [:bz] (still a bit busy) 2016-09-05 21:19:10 PDT
> Boris, can you elaborate on that?

The issue is that Gecko's style system can't compute style for things in a display:none iframe, because style computation is tied to the presshell, and there isn't one.

Though maybe the answer is that there should in fact be a presshell but frame construction should be suppressed.  (Or allowed, with an assumption of 0x0 size for the presshell; arguably that's what the CSS spec calls for, but it's ridiculously inefficient and I don't think we want to go there.)
Comment 32 User image Bobby Holley (:bholley) (busy with Stylo) 2016-09-20 16:49:35 PDT
I think Stylo doesn't really offer a super-clean way to fix this. Most of the per-document state is set up via presshell initialization, and we can't construct style structs without a prescontext.

So I think the issue is mostly orthogonal. If it's invasive and not urgent I'd still rather we punt on it for now though, since it'll touch a lot of the same code.
Comment 33 User image Boris Zbarsky [:bz] (still a bit busy) 2016-09-22 17:55:17 PDT
OK.  So I talked to dbaron, and he's on board with the plan in comment 31.  I don't think changing that will affect stylo much, if any.

This came up again today in https://github.com/hakimel/reveal.js/issues/1546 though it's not clear to me whether the comment 31 approach will actually fix that site, because it might still result in things looking 0-sized.
Comment 34 User image David Baron :dbaron: ⌚️UTC-8 2016-10-20 11:08:55 PDT
Yeah, having a pres shell seems like fewer special cases.

That said, maybe it's worth pinging the Chromium folks and seeing if they're interested in trying to change their behavior, given that not constructing things when display:none seems like a more efficient behavior.
Comment 35 User image Boris Zbarsky [:bz] (still a bit busy) 2016-10-20 11:12:39 PDT
> maybe it's worth pinging the Chromium folks and seeing if they're interested in trying
> to change their behavior

Did that already.  See https://github.com/whatwg/html/issues/1813
Comment 36 User image Johnny Stenback (:jst, jst@mozilla.com) 2016-10-21 23:59:24 PDT
This is unfortunately breaking opentable.com, which is something we'd like to fix sooner rather than later. See bug 1302780
Comment 37 User image Boris Zbarsky [:bz] (still a bit busy) 2016-10-22 18:03:38 PDT
> This is unfortunately breaking opentable.com

Yes, that's the site that led me to get back to this in comment 28.

I've been working on this on and off per my plan from comment 31, but what I have so far is _very_ orange on try: see <https://treeherder.mozilla.org/#/jobs?repo=try&revision=88f5506602d5bd66d688fc8cabd3ffa58d9a5916>.  I've slowly been working through some of the failures, but I could drop other things for a bit and really focus on this if we think the opentable breakage is important enough.  Unfortunately it's failures in all sorts of different parts of the code, not just a case of the same failure happening in lots of test suites.  :(

Note You need to log in before you can comment on or make changes to this bug.