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

Mis-fires in Chrome/Mac and all iOS7 browsers #79

Open
brendanfalkowski opened this issue Oct 10, 2013 · 25 comments
Open

Mis-fires in Chrome/Mac and all iOS7 browsers #79

brendanfalkowski opened this issue Oct 10, 2013 · 25 comments

Comments

@brendanfalkowski
Copy link

This is an issue that affects the native matchMedia, Enquire, and Harvey: https://github.com/harvesthq/harvey

Follow-up from this Twitter conversation: https://twitter.com/Falkowski/status/387294544988889089

See test case: http://cdn.gravitydept.com/matchmedia/

I also setup a test in CodePen, but I'm not sure this is representative since it loads within an iframe even in full-screen mode.

See test-case in CodePen: http://codepen.io/brendanfalkowski/pen/qCauf
Full screen: http://codepen.io/brendanfalkowski/full/qCauf


Chrome/Mac has an off-by-one error

Chrome Version 30.0.1599.69

If the browser is 1200px, then resized to 1023px ➔ the (min-width:1024px) query is not unmatched until 1022px.

Opposite: if the browser is 1000px, then resized to 1024px ➔ the (min-width:1024px) query is not matched until 1025px.

This seems to affect matchMedia, Enquire, and Harmony equally in Chrome. Firefox, Safari, and Opera calculate correctly.


iOS 7 orientation change bug

Safari and Chrome for iOS 7 do not fire min-width or max-width queries on orientation change.

In my demo, media queries only fire if the browser is refreshed, but min-width:1024px should fire in iPads on orientation change.

In the CodePen, no media queries fire on refresh so I'm pretty sure the iframe is preventing some behavior.

@brendanfalkowski
Copy link
Author

@WickyNilliams
Copy link
Owner

Since these bugs are demonstrable in the matchMedia API, I'd say there's little I can do about it except wait for the bug to be fixed. Do you think I should just close this issue on those grounds?

@brendanfalkowski
Copy link
Author

Unsure of the issue etiquette, but since the bug is technically affecting it might be useful to keep open if others have the same issue.

@va7map
Copy link

va7map commented Oct 16, 2013

Have you tried commenting out the Harvey events? When I did that, both Enquire and matchMedia events get fired on orientation change. Seems to me that Harvey is contributing to or causing the problem.

@brendanfalkowski
Copy link
Author

@va7map Thanks! Great idea, that does work as expected. Removing Harvey solved the Chrome off-by-two issue and the iOS7 orientation bugs.

Removing Enquire did not have the same effect, so it appears this is actually a Harvey issue though I'm not sure how it's impacting Enquire and the native matchMedia query. I'll update the other reports and test-case to reflect this.

@va7map
Copy link

va7map commented Oct 16, 2013

You're welcome @brendanf. I just happen to be dealing with a similar issue. I'm not using Harvey, so something else must be causing it...

@sachinjsk
Copy link

I ran into the same issue and I'm not using Harvey either.

@brendanfalkowski
Copy link
Author

@va7map and @sachinjsk What other JS is included when you experience the issue? In my reduced case it was jQuery 1.10.1 and Harvey (which was causing the issue). Wondering what other libs are causing conflicts. Might be able to isolate a common component or practice between the offenders.

@WickyNilliams
Copy link
Owner

@sachinjsk can you whip up a little fiddle/codepen to demo the problem (ideally a reduced test case)?

@va7map
Copy link

va7map commented Oct 24, 2013

I was able to isolate the cause of the issue I'm seeing. Basically, if there are similar CSS media queries on the page, the matchMedia listeners won't get called right away, until the browser is further resized by another pixel.

I've filed a bug with WebKit (link), and here's a test page you can try: https://bug-123293-attachments.webkit.org/attachment.cgi?id=215113

@sachinjsk
Copy link

Here's my test case - http://bit.ly/1cgEkst

That test case works fine if you remove the media query definition from CSS.

I created a codepen (http://codepen.io/sachinjsk/pen/bcqzh) with the exact same code, and that works fine(even with the media query definition in CSS).

@va7map
Copy link

va7map commented Oct 25, 2013

@sachinjsk If you slowly resize your browser pixel by pixel, and compare the results between Firefox 24 and Chrome 30, you should notice that in Firefox (which isn't affected by this bug), the transition between matched and unmatched happens at the same time the text color changes. But in Chrome 30 (or Safari 6.1) the color changes first. The actual matching or unmatching doesn't happen for another pixel. And that's exactly the same issue in my test case.

By the way, your test case on Dropbox has an error on Firefox 24 and Chrome 30, because they now block insecure content. You can remove "http:" in src attribute of the scripts so it's relative to the protocol.

@brewt
Copy link

brewt commented Oct 29, 2013

I've simplified @sachinjsk's test case a bit:

http://devrandom.com/test/ios7-matchmedia/

You can see that things are fine if you embed that url inside an iframe:

http://devrandom.com/test/ios7-matchmedia/iframe.html

Don't see how that really helps (just an explanation to why @sachinjsk's codepen worked), but one thing that did help was that I found that triggering a reflow/repaint would fix things:

http://devrandom.com/test/ios7-matchmedia/fixed.html

Not a pretty fix at all (and I don't think it's something I would commit into enquire.js), but for anyone who needs things to work in iOS7, this bit of JavaScript seems to work for me:

(function () {
    if (document.addEventListener) {
        document.addEventListener('DOMContentLoaded', function () {
            var shim = document.createElement('div');
            shim.id = 'ios7-matchMedia-fix';
            document.body.appendChild(shim);

            var timer,
                forceReflow = function () {
                    shim.style.width = (window.innerWidth / 2) + 'px';
                },
                onResize = function () {
                    clearTimeout(timer);
                    timer = setTimeout(forceReflow, 100);
                };

            window.addEventListener('resize', onResize, false);
        });
    }
})();

The width itself doesn't seem to be important (just made it / 2 as to avoid overflow). Probably could optimize the code a little more by only running on iOS user agents and possibly removing the timer since the resize event shouldn't be triggering continuously on iOS like it does in IE.

Edit: Forgot to mention that this looks like an iOS7 bug, not an enquire.js bug.

@va7map
Copy link

va7map commented Oct 29, 2013

@brewt Your iframe-embedded test case didn't work for me on the desktop (it did work on the iPad though). It behaves the same way as the non-iframe one. This is what I see on Chrome 30 and Safari 6.1:

  • ≤ 768px — matched (red text)
  • 768px -> 769px — matched (black text), which shows that there is a bug
  • 769px -> 770px — un-matched (black text)

I also found that triggering a reflow/repaint fixes the problem.

@brendanfalkowski
Copy link
Author

As mentioned in the original report, an iframe test cannot be trusted because the parent page may not be rendered at native size if the "viewport" meta tag isn't set to prevent scaling. Thus some devices will not trigger the issue if the example is narrower than the device's native viewport and scale value. To test accurately, you have to load a static page with the viewport tag set.

@va7map In my project (now Harvey-less) I do have CSS media queries firing on the same query as Enquire, and I'm not experiencing the issue. So that may not be a cause.

@WickyNilliams
Copy link
Owner

For the repaint, could you not just read any property on anything and then write that exact value back? e.g. window.scrollY = window.scrollY? Slightly simpler than creating new nodes etc...

So this has gone back and fore a few times now, and I'm having difficulty keeping tracking of things (could just be me!). Can we summarise everything we know so far e.g. affected browsers, whether it is reproducible with just the underlying matchMedia API etc?

@va7map
Copy link

va7map commented Oct 29, 2013

@WickyNilliams From my testing, Safari started exhibiting the problem in iOS 7 and since 6.1 on OS X, so my guess is any browsers using WebKit 537 or later. It is reproducible with the basic matchMedia API, when there is a similar CSS media query present. The effect is that the matchMedia listener will not be called initially when there is a change to the media query results (e.g. when rotating and iPad from portrait to landscape). On the desktop, resizing the browser window further will fix it.

@brendanf I'd be interested to see the counter-example you mentioned. Can you please post that somewhere for us to look at?

@brendanfalkowski
Copy link
Author

@va7map Seems I spoke too soon.

My original test case without media queries which is working properly:
http://cdn.gravitydept.com/matchmedia/

When I added a CSS media query at 1024px (change body color), the bug DOES return:
http://cdn.gravitydept.com/matchmedia-with-mq/

You can see the CSS media query applies, but the JS matchMedia does not (as the bug was described initially). This demonstrates there is a fault occurring when both JS and CSS media queries are applied.

@va7map
Copy link

va7map commented Jan 15, 2014

Quick update for Mac browsers: the bug is still present in Safari 7.0.1, but is absent/fixed in Chrome 32.0.1700.77 (probably Chrome 31 as well).

@brendanfalkowski
Copy link
Author

Ran some tests to confirm @va7map's latest updates:

Confirmed working:

  • Chrome for Mac, 32.0.1700.77
  • Firefox for Mac, 26.0

Not working:

  • Chrome for iPad, 31.0.1650.18
  • Safari for Mac, 7.0.2
  • Safari for iPad, iOS 7.0.4

@mderrick
Copy link

I have also found this issue on iOS7.

@WickyNilliams Unfortunately window.scrollY = window.scrollY and some other forms of forcing a repaint didn't seem to work.

The only ones that worked for me were appending an element as mentioned above and setting the body width:

$('body').width(1).width(''); which I found preferable to appending an extra DOM node.

Further to @brewt's solution you only need to set the timer to 0 so it is deferred to the end of the call stack.

timer = setTimeout(forceReflow, 0);

If anyone has a tidier solution, I'd love to know.

@WickyNilliams
Copy link
Owner

Guys, apologies for being elusive... I have a load of time this week to investigate this.

Can someone confirm whether the big was ever present on iPhone or just iPad? I now have an iPhone for testing, and can probably grab an iPad this week if need be.

@brendanfalkowski
Copy link
Author

Don't think I tested on iPhone because the breakpoint I needed only affected iPad-sized devices. The tests I put together should still be accessible, but you could pretty quickly modify the breakpoint to suit whatever size/generation the iPhone you have is. (They were off-by-one errors, so the exact dimension matters more than setting an obvious gap between orientations).

@va7map
Copy link

va7map commented May 12, 2014

The issue is present in Safari on Mac OS X as well, and it doesn't seem to depend on a specific resolution. Based on this, I'd say it affects the iPhone too.

@ryanfitzer
Copy link

I was not able to reproduce this in Safari 12 on macOS Sierra using the test page @va7map attached to the bug report.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants