Bug 170595 - window.innerWidth/innerHeight are bogus after resize/orientationchange in WKWebView (but not MobileSafari)
Summary: window.innerWidth/innerHeight are bogus after resize/orientationchange in WKW...
Status: NEW
Alias: None
Product: WebKit
Classification: Unclassified
Component: Layout and Rendering (show other bugs)
Version: Other
Hardware: iPhone / iPad iOS 10
: P2 Major
Assignee: Nobody
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2017-04-07 03:54 PDT by ae
Modified: 2023-08-21 20:10 PDT (History)
24 users (show)

See Also:


Attachments
test page (1.26 KB, text/html)
2017-04-21 12:00 PDT, Tim Horton
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description ae 2017-04-07 03:54:03 PDT
When my iPhone SE is rotated from portrait to landscape or vice versa, both resize and orientationchange events are generated on window (OK). However, in the respective event handlers, window.innerWidth/innerHeight have useless / bogus values. For example, in a resize handler, they'll BOTH (!) be 320 (last time I checked, my iPhone wasn't square), and in the orientationchange handler, it will still have the values from the PREVIOUS orientation.

This is a major showstopper for hybrid apps that aim to support both orientations.

Introduced in iOS 10.3.1. 10.2 was fine.
Comment 1 ae 2017-04-07 03:55:04 PDT
(this occurs in WKWebView)
Comment 2 Radar WebKit Bug Importer 2017-04-07 08:46:12 PDT
<rdar://problem/31501450>
Comment 3 Ali G 2017-04-11 11:08:04 PDT
This also broke AMP's image viewer in 10.3: https://github.com/ampproject/amphtml/issues/8479 

Prioritized commitment to fix this would be very much appreciated.
Comment 4 Sriram Krishnan 2017-04-11 11:13:03 PDT
This affects a large subset of AMP pages (likely a few 100 million). This will represent a significant regression in UX.
Comment 5 ae 2017-04-11 11:22:32 PDT
If anyone is interested and/or trying to find a workaround for their situation: Both events are completely useless right now, as they never get called with the correct values for innerWidth/Height in place.

The quick fix I immediately deployed in my production apps was to just introduce a timeout in the orientationchange handler (0.7s), as I hoped that after 0.7 seconds, the values are finally correct (seems to be the case).

The "real" fix was to constantly check both innerWidth and innerHeight (say, 10 times per second) and if any of them changes, generate a "fake" resize event. That works, but is of course a waste of CPU and battery.
Comment 6 Tim Horton 2017-04-21 11:56:15 PDT
Hello! Can you, by any chance, attach a test app that reproduces the regression? I can reproduce the problem, but I can *also* reliably reproduce it in earlier versions of iOS, so I'm not sure I'm testing the same thing as you.
Comment 7 Tim Horton 2017-04-21 12:00:48 PDT
Created attachment 307766 [details]
test page
Comment 8 Tim Horton 2017-04-21 13:44:12 PDT
OK, the AMP problem is actually not a duplicate of this. Splitting that out into https://bugs.webkit.org/show_bug.cgi?id=171140.
Comment 9 ae 2017-04-22 08:27:17 PDT
(In reply to Tim Horton from comment #6)
> Hello! Can you, by any chance, attach a test app that reproduces the
> regression? I can reproduce the problem, but I can *also* reliably reproduce
> it in earlier versions of iOS, so I'm not sure I'm testing the same thing as
> you.

Hello. I'm not completely sure really what changed and when, all I know is that the app's orientation change handling was broken the moment I updated to iOS 10.3.1. 

Here's some debug output from the handlers (window.orientation in parentheses) :

--- After rotating the phone from portrait to landscape: ---

ORIENTATIONCHANGE: 320 x 568 (90)
RESIZE: 320 x 320 (90)
App.resize (from update): 568 x 320

- wrong (old portrait) dimensions in orientationchange handler
- wrong dimensions in resize handler (square!)
- App.resize is the "fake" handler I wrote which manually detects size changes (fine)

--- After rotating back to portrait: ---

ORIENTATIONCHANGE: 568 x 320 (0)
RESIZE: 320 x 320 (0)
App.resize (from update): 320 x 568

- wrong (old landscape) dimensions in orientationchange handler
- wrong dimensions again in resize handler

Note that there's NEVER a correct 'resize' event generated with the correct values for innerWidth/innerHeight!

Hope this helps. Probably a difficult one to get fixed.
Comment 10 dopıng 2017-04-23 06:06:44 PDT
No idea whether this is related, but just in case…

There’s also been another change in the behavior of ‘window.innerHeight’ between iOS 10.2 and 10.3.1:
When you touch an input field that’s located at the bottom of a page, the virtual keyboard comes up and Safari scrolls to ensure that the field remains visible. If you have a handler attached to the window’s ‘scroll’ event and read ‘window.innerHeight’ in it, in iOS 10.2 the height was unchanged, i.e. not reduced by the height of the keyboard. In iOS 10.3.1, it *is* reduced by the height of the keyboard.
Comment 11 Tim Horton 2017-04-24 12:59:38 PDT
(In reply to ae from comment #9)
> 
> Hello. I'm not completely sure really what changed and when,

Right, but I need to figure that out, so I can fix it!

> all I know is that the app's orientation change handling was broken the moment I updated to iOS 10.3.1. 
> 
> Here's some debug output from the handlers (window.orientation in
> parentheses) :

Can you reduce the app to something you're willing to share? Either here, or at bugreport.apple.com if you would prefer?

> Note that there's NEVER a correct 'resize' event generated with the correct
> values for innerWidth/innerHeight!
> 
> Hope this helps. Probably a difficult one to get fixed.

If you can't reduce the app to something you can share, perhaps you could look at the test page that I attached and see what might be different between it and your app that causes this problem to not reproduce in the test page?

I need to get to the point where I can reproduce the problem in order to diagnose.
Comment 12 Tim Horton 2017-04-24 13:06:04 PDT
(In reply to Tim Horton from comment #11)
> (In reply to ae from comment #9)
> > 
> > Hello. I'm not completely sure really what changed and when,
> 
> Right, but I need to figure that out, so I can fix it!
> 
> > all I know is that the app's orientation change handling was broken the moment I updated to iOS 10.3.1. 
> > 
> > Here's some debug output from the handlers (window.orientation in
> > parentheses) :
> 
> Can you reduce the app to something you're willing to share? Either here, or
> at bugreport.apple.com if you would prefer?
> 
> > Note that there's NEVER a correct 'resize' event generated with the correct
> > values for innerWidth/innerHeight!
> > 
> > Hope this helps. Probably a difficult one to get fixed.
> 
> If you can't reduce the app to something you can share, perhaps you could
> look at the test page that I attached and see what might be different
> between it and your app that causes this problem to not reproduce in the
> test page?
> 
> I need to get to the point where I can reproduce the problem in order to
> diagnose.

Sorry, I forgot the context. Rather, I need to figure out why your app *didn't* reproduce in older versions of iOS, when the test page does.
Comment 13 Simon Fraser (smfr) 2017-05-08 13:22:21 PDT
We're sending a visible rect update with unobscuredContentRect (0,0) width=320 height=320) during rotation.
Comment 14 Simon Fraser (smfr) 2017-05-08 13:29:18 PDT
We end up with 320x320 by virtue of:

    unobscuredRectInContentCoordinates = CGRectIntersection(unobscuredRectInContentCoordinates, [self _contentBoundsExtendedForRubberbandingWithScale:scaleFactor]);
Comment 15 Simon Fraser (smfr) 2017-05-08 13:34:45 PDT
and that's because we haven't update the contentView bounds for rotation yet (this happens on a callback from the web process), so we're intersecting 320x568 with 548x320.
Comment 16 Simon Fraser (smfr) 2017-05-08 17:34:22 PDT
We can fix this by avoiding the intersection with the content view bounds (which is really just there to fix rubber banding), but the layout viewport rect is still wrong because it also relies on state from the web process (the documentRect).

We really need to round-trip through the web process with the new size before we can reliably compute rects.
Comment 17 ae 2017-05-09 01:33:52 PDT
Sorry I couldn't provide a real testcase yet, just completely drowned in work. But as it seems, you've already found the problem. Thanks again for looking into this.
Comment 18 Ali G 2017-12-08 15:13:43 PST
Hi Webkit team,

Given Simon has found the root cause and has a proposed fix here, is this something we can expect to see fixed soon? 

Current workaround with introducing 500ms+ delays really hurts users' expectations of great UX.

Thank you
Comment 19 Cathy Z 2017-12-11 17:54:52 PST
Not
Comment 20 Cathy Z 2017-12-11 17:58:26 PST
Sorry, meant to find a way to subscribe / +1 to this bug, but accidentally saved a comment.
Comment 21 Matthew Henry 2018-01-30 03:49:57 PST
(In reply to Ali G from comment #18)
> Hi Webkit team,
> 
> Given Simon has found the root cause and has a proposed fix here, is this
> something we can expect to see fixed soon? 
> 
> Current workaround with introducing 500ms+ delays really hurts users'
> expectations of great UX.
> 
> Thank you

Ali, I'm not sure whether this will be relevant to you given that it's been a month or so since your comment, but I've had success with a zero-delay workaround by calling getBoundingClientRect() on an element that's been styled to fill 100% of the window size within the window's resize handler.
Comment 22 Ilya G. 2018-06-04 07:27:22 PDT
Is this bug actually fixed in iOS 11.4?
Comment 23 Maxim Ambrosevich 2018-06-05 03:51:48 PDT
Unfortunately, yes. Test on PWA app.
Comment 24 Ozmor 2018-08-31 01:01:03 PDT
I'm still have the same problem, I need to put time out to make it work. Does anyone have any other solutions ?
Comment 25 Mo Lam 2018-12-18 22:50:43 PST
A slightly different workaround:

To avoid creating a new element, The following workaround seems to work fairly well for me:

For non-Safari, get the layout viewport size from document.documentElement.clientHeight (& Width).

Unfortunately, Safari's documentElement size does not update when the URL bar hides so I couldn't just apply it to all Webkit browser, but this bug just doesn't happen to Safari.
Comment 27 dennis.subachev1 2019-11-12 11:57:03 PST
Can confirm I still see this issue. I threw the test page up on stackblitz for anyone who wants to try themselves: https://typescript-pmaukj.stackblitz.io

Going portrait -> landscape -> portrait will cut off a space at the bottom of the screen the size of the menu (footer?) bar. `window.innerHeight` will _not_ include the cut off region so there is nothing that can be done to fill it until the user scrolls. This is especially a problem in our web app because we have `overflow-y: scroll` type containers that have a min and max height of `window.innerHeight`.
Comment 28 ztforster 2020-06-05 18:52:28 PDT
I am seeing the same issue in iOS 13.3.1, also in a WKWebView. I was able to work around it by implementing the solution "constantly check both innerWidth and innerHeight (say, 10 times per second)". I feel very strongly about this, as I don't rightly understand why you'd even bother implementing the resize event if window dimensions aren't going to be accurate. The way it is now, you need this hack to implement any kind of SVG visualization that needs a different aspect ratio in landscape.
Comment 29 Simon Fraser (smfr) 2023-08-21 20:09:39 PDT Comment hidden (obsolete)
Comment 30 Simon Fraser (smfr) 2023-08-21 20:10:08 PDT Comment hidden (obsolete)