Skip to content
This repository has been archived by the owner on Jan 9, 2023. It is now read-only.

Content dimensions incorrect at startup on iPhone X #108

Closed
xtassin opened this issue Jul 26, 2019 · 53 comments
Closed

Content dimensions incorrect at startup on iPhone X #108

xtassin opened this issue Jul 26, 2019 · 53 comments

Comments

@xtassin
Copy link

xtassin commented Jul 26, 2019

As described in this original issue #53, the document body's first child is incorrectly sized when starting the application. The issue is gone after rotating the device and back to original orientation. The body dimensions appear to be always correct though.
This only occurs on iPhone X and likes.

A fix for this issue, provided in #45, was recently reverted in #107

@dpogue
Copy link
Member

dpogue commented Jul 26, 2019

  1. What is the value of the viewport meta tag?
  2. Is the body's first child element using height: 100% or height: 100vh?

The fix in #45 is not a fix because it takes control of the webview behaviour away from the app developer and unilaterally enforces a decision about the handling of safe areas on all Cordova apps. That change is already known to break several existing apps that are handling safe areas properly, which is why it was reverted.

@xtassin
Copy link
Author

xtassin commented Jul 26, 2019

  1. "width=device-width, height=device-height, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, viewport-fit=cover"
  2. I tried with both % and vh with the same result

I understand #45 fix may not be a viable solution. However, I believe the sizing issue is most likely a bug and not a misuse of CSS or Markup.

Again, sizing is correct once device has been rotated or some other reflow event occurs (resize, etc.)

I fixed my app temporarily with a fork of #45 but I would love to see a proper solution that would fit everyone needs.

Thank you.

@jacobweber
Copy link

Doesn't #45 give more control to the app developer, by letting them manage the insets using CSS, instead of adding them automatically? I suppose it could be configurable though.

@dpogue
Copy link
Member

dpogue commented Jul 26, 2019

It is not the job of Cordova to make those decisions. It is up to the app developer to say what they want with their viewport-fit meta tag.

@dominic-simplan
Copy link

dominic-simplan commented Aug 1, 2019

@xtassin I had the same issue as you're describing. It was a bit trial-and-error with the height settings, but I think this example repository should demonstrate a working setup. If not, maybe you can modify it and show your issue?

(Yet I agree that it is strange that the described issue only occurs initially and is gone after rotating the device...)

@xtassin
Copy link
Author

xtassin commented Aug 3, 2019

Hi Dominic,

I am sorry but I can't get the expected result when running your example.

I built it with PhoneGap Build and ran it in app-live.browserstack.com

As you can see from the screenshot, the viewport does not extend to the full iPhone screen size.

It seems like the splashscreen image is ignored.

image

Did I miss something?

@dominic-simplan
Copy link

@xtassin sorry, no idea, I am running it directly on a Mac in a simulator:
grafik

Can you see the splashscreen during startup? The splashscreen is defined in the config.xml, but maybe something is wrong with the definition?

deedw added a commit to deedw/cordova-plugin-wkwebview-engine that referenced this issue Aug 19, 2019
This fix was applied but then reverted in apache/cordova-plugin-wkwebview-engine. 

See apache#108
@onaluf
Copy link

onaluf commented Aug 27, 2019

I've got the exact same issue as @xtassin (fine after rotate) and the fix from @deedw fixes it

@jacobweber
Copy link

@onaluf Right, but that's the same fix as in #45, so it won't get merged back into master.

Not sure what the solution is. I have this issue with the viewport tag width=device-width,height=device-height,user-scalable=no,initial-scale=1,maximum-scale=1,minimum-scale=1,shrink-to-fit=no,viewport-fit=cover and the body's first child set to height: 100%.

@dpogue
Copy link
Member

dpogue commented Aug 27, 2019

Try setting the body or the body's first child to height: 100vh? I've noticed a difference between 100% and 100vh on WKWebView.

@onaluf
Copy link

onaluf commented Aug 27, 2019

@dpogue Yes 100vh does work if I set it on an element on the page. Doesn't change anything if I directly apply it to html or body though

@deedw
Copy link

deedw commented Aug 27, 2019

I ended up having to fork and reapply the fix from #45 to get it working reliably.

@dominic-simplan
Copy link

@onaluf @deedw Here is an example repository which shows the correct behavior in the iOS simulator. Does this not work for you? Or otherwise, can you provide a simple repository which demonstrates your issue?

@onaluf
Copy link

onaluf commented Aug 28, 2019

Hi @dominic-simplan, yes the example work. This version doesn't though: https://github.com/onaluf/wkwebview . What I did there is:

  • remove the padding that used the safe area inset
  • made the container position absolutely

With those two changes the page will behave like @xtassin described: the container will only fill the screen partially until the device is rotated, which to me is where the bug really is. Even if the behaviour we want is having the container not take the full screen it shouldn't change once you rotate the device...

On a side note with height: 100vh the issue disappear.

@dpogue
Copy link
Member

dpogue commented Aug 28, 2019

the container will only fill the screen partially until the device is rotated, which to me is where the bug really is. Even if the behaviour we want is having the container not take the full screen it shouldn't change once you rotate the device...

This is a bug in Webkit that should be reported to Apple. It's not something Cordova can workaround without breaking the behaviour of existing apps.

On a side note with height: 100vh the issue disappear.

This should be the solution to most of the problems people encounter with the safe area insets. For reference, here are the changes we made to update the "Hello Cordova" example app.

@meishier
Copy link

hi, @onaluf,

On a side note with height: 100vh the issue disappear.

I git clone your https://github.com/onaluf/wkwebview , the issue does not disappear. After app boots, it still only fill the screen partially.

@onaluf
Copy link

onaluf commented Sep 10, 2019

@meishier did you set the height on the container div? It doesn’t work if you set it to the body/html element

@meishier
Copy link

@onaluf, thank you very much

html/body 100%
#container 100%, not works

html/body 100%
#container 100vh, works

@spinninghamster
Copy link

spinninghamster commented Sep 30, 2019

It's working for me fine in the Mac simulator without the 100vh. Am I affected by this bug in real devices? Or am I fine if it works for me in the simulator?

It would appear this only happens if the container is position: absolute;?

@jacobweber
Copy link

So far the suggested fix is working for me. I already had viewport-fit=cover and head/body at 100% x 100%. I changed the first visible child element of body from 100% x 100% to 100vw x 100vh, and I'm no longer seeing the extra margin.

I'm wondering how reliable this is, e.g. if additional child elements of body are added with 100% instead of 100vw, will that re-introduce the margin? Or is it only calculated when the app launches?

BTW, the issue never appeared every time -- I would usually need to re-launch it a few times for it to appear.

@jespertheend
Copy link

jespertheend commented Oct 1, 2019

@spinninghamster I think you're fine on real devices if it works in the simulator. I'm running my app in the simulator and I am actually seeing a huge white border at the bottom. This is happening both in the simulator as well as on a physical device.
image

@dpogue using height: 100vh on the body does make the body full height, but unfortunately window.innerHeight still reports the incorrect height. So a lot of my UI, including my full screen canvas, gets scaled/positioned incorrectly. I get that the fix in #45 is not a clean solution and breaks existing apps. But it would it be possible to still have this functionality using a preference in cordovas config.xml for example?

@dpogue
Copy link
Member

dpogue commented Oct 1, 2019

@jespertheend Are you setting viewport-fit=cover in your meta viewport tag?

@jespertheend
Copy link

@dpogue yes

@jespertheend
Copy link

jespertheend commented Oct 1, 2019

Hmm I'm actually getting the correct value from window.innerHeight now. I'll do some more investigating...

@jespertheend
Copy link

jespertheend commented Oct 1, 2019

@dpogue ah I see, I was running a different emulator which had a different screen size. That got me confused for a bit. Yeah it does seem to report the wrong height: 818 (on 11 Pro Max) and when I rotate the device and rotate it back, it reports (896). On iPhone X it's 734 and 812 respectively.

I reverted back to 1.2.0 for now since it seems to work fine there.

@lovelyelfpop
Copy link

Make UIScrollViewContentInsetAdjustmentNever be a configuration would be nice.

@dpogue
Copy link
Member

dpogue commented Oct 11, 2019

@lovelyelfpop It is configurable, via your page, using viewport-fit=cover. That causes WKWebView to apply UIScrollViewContentInsetAdjustmentNever to the webview.

@lovelyelfpop
Copy link

@dpogue I already use viewport-fit=cover, but still seeing a blank area at the bottom

@ghost ghost mentioned this issue Dec 12, 2019
@DuBistKomisch
Copy link

the fact that the height changes before and after rotating means to me that this is clearly an underlying bug, if not in cordova than iOS itself. I also have an issue where the window innerWidth and innerHeight are reported as both the same in the window 'resize' event listener (workaround is to setTimeout(100) derp), so there seems to be some race issue with the window size in general?

I will try the 100vh workaround as soon as I have a chance, but that still doesn't fix window.innerHeight reporting the wrong value, I guess we need to read the real width/height of the body tag or something?

👍 to exposing a cordova preference to work around this bug

@Pigsnuck
Copy link

Pigsnuck commented Jan 7, 2020

I will share my solution for all those other frustrated developers. I was fiddling around with this issue for quite some time also. I experienced the issues with WkWebkit here too, but the following steps resolved all issues for me. The main thing to note is that upgrading my project DID NOT WORK. I had to completely rebuild it. I'm not sure which file change made the difference, but

  • Ran cordova plugin ls and saved the results.
  • Removed all cordova platforms (cordova platform rm ios, etc).
  • Deleted the /plugins folder.
  • Updated cordova to the latest version (just to be sure - it was already the latest for me).
  • Reinstalled all platforms.
  • Reinstalled all plugins (especially cordova-plugin-webkit and the localserver plugins to use http://localhost:8080).
  • Applied the viewport meta-tag.

After these steps, everything ran full-screen correctly without any bugs. Like any good developer, I immediately checked everything into source control.

Then I copied my Images.xcassets file containing my logos and screenshots over to the /platforms/ios directory. After that, I started experiencing all the problems above again. I had to rebuild this file manually.

Lindsay-Needs-Sleep added a commit to miloproductionsinc/cordova-plugin-ionic-webview that referenced this issue Mar 21, 2020
This denies users control.
- Remove both methods that force "UIScrollViewContentInsetAdjustmentNever".
- See @dpogue's comments for reasoning: apache/cordova-plugin-wkwebview-engine#108
- Added some documentation that helps users configure their view properly for devices that have safe-insets due to "the notch" like iPhone X.  (So that they can acheive the same behavior as this change was doing if desired).
Lindsay-Needs-Sleep added a commit to miloproductionsinc/cordova-plugin-ionic-webview that referenced this issue Mar 21, 2020
This denies users control.
- Remove both methods that force "UIScrollViewContentInsetAdjustmentNever".
- See @dpogue's comments for reasoning: apache/cordova-plugin-wkwebview-engine#108
- Added some documentation that helps users configure their view properly for devices that have safe-insets due to "the notch" like iPhone X.  (So that they can acheive the same behavior as this change was doing if desired).
Lindsay-Needs-Sleep added a commit to miloproductionsinc/cordova-plugin-ionic-webview that referenced this issue Mar 23, 2020
This denies users control.
- Remove both methods that force "UIScrollViewContentInsetAdjustmentNever".
- See @dpogue's comments for reasoning: apache/cordova-plugin-wkwebview-engine#108
- Added some documentation that helps users configure their view properly for devices that have safe-insets due to "the notch" like iPhone X.  (So that they can acheive the same behavior as this change was doing if desired).
See PR ionic-team#530 for details
Lindsay-Needs-Sleep added a commit to miloproductionsinc/cordova-plugin-ionic-webview that referenced this issue Mar 23, 2020
This denies users control.
- Remove both methods that force "UIScrollViewContentInsetAdjustmentNever".
- See @dpogue's comments for reasoning: apache/cordova-plugin-wkwebview-engine#108
- Added some documentation that helps users configure their view properly for devices that have safe-insets due to "the notch" like iPhone X.  (So that they can acheive the same behavior as this change was doing if desired).
See PR ionic-team#531 for details
@peterfox1
Copy link

Just to add in case anyone is still getting this & finds this issue - I found that the following style can cause the gap to remain even when you have the viewport set + 100vw/vh.

html {
	position: fixed;
}

If you happen to have this style set, you may need to remove it.

@brodycj
Copy link

brodycj commented Mar 25, 2020

We maintainers do not have the resources to actively support closed issues. I suggest raising a documentation issue here: https://github.com/apache/cordova-docs/issues

@louisameline
Copy link

louisameline commented Apr 1, 2020

I will say again that this is not a Cordova bug. If you are seeing problems then it's related to your HTML content and the meta tags and stylings in your content.

Please reopen the issue. Or please explain how on Earth I can have in the console:

  • at page load, window.innerHeight returns 734
  • after a rotation to landscape and back to portrait, window.innerHeight returns 812

734 = 812 (actual screen height) - 44 (top safe area inset) - 34 (bottom safe area inset).
So, I'm not Einstein but I'd say that at page load and until rotated, the window.innerHeight wrongfully subtracts the safe area insets. This can be demonstrated even in a blank page.

I will also add that the issue happens ONLY if the content of page is smaller in height than the window height. Exemple: if the "natural height" of my page is 500, window.innerHeight returns 734 as I said. If my page content is 750px high, window.innerHeight will return 750, and if my page content overflows the window, window.innerHeight will return 812.

Also, the Ionic-maintained WKWebView plugin fork doesn't have this bug, my guess is that they must have seen it and fixed it. Maybe their fix can be cherry picked?

As for other platform, the bug doesn't happen in Chrome, Safari, UIWebView, Ionic WKWebView, Capacitor.

The bug was prevented in my case by adding height: 100vh; to the html element.

I also found that inserting this at the very beginning of the body was working, except when the body has position: fixed;:

<div style="height: 100vh; position: absolute; visibility: hidden; width: 1px;"></div>

For the record, I had previously found another quirky workaround:

body {
	display: contents;
}
// I personally put this in the "mounted" (rendered) hook of my Vue app
const style = document.querySelector('#someContentElement').style
style.minHeight = '1000px'
setTimeout(() => {
	style.minHeight = ''
}, 100)

This made the body overflow the window for just a moment, so innerHeightgets the expected value. display: contents makes sure that the innerHeight doesn't get back to the wrong value after you remove the overflow. I don't know why exactly, but it works.
Caveat due to display: contents; though: the padding and margin of the body, if any, will not be enforced anymore, you'll have to set it on children elements instead. Also, a background set on the body will not work anymore, but you can set it on the html tag instead. Finally, your page will lose accessibility (for visually impaired people and such). And there were other quirks with scrolling, positioning, the keyboard...

I'm using iPhone XS, iOS 13.4, Xcode 11.4, cordova-ios 5.1.1, cordova-plugin-wkwebview-engine 1.2.1, viewport-fit=cover.

@louisameline
Copy link

louisameline commented Apr 4, 2020

@dpogue and any other Cordova maintainer: I can easily share a project to replicate the issue (a blank page is enough to demonstrate the issue). Or can you please confirm that Cordova cannot possibly be responsible for what I explained and that I should open a ticket in the Webkit bug tracker instead? Thank you
Edit: I did open a ticket https://bugs.webkit.org/show_bug.cgi?id=210009

@fmiguelroliveira
Copy link

I've tried all the possible fixes and no one works. I'm still having wrong height dimensions.

In my project i don't have any container. I'm working with display blocks inside html/body.

BTW is there a probably solution like triggering the rotation just to fix dimensions?

This is just annoying...we should not have to care about this kind of issues, that takes us time and money...

@louisameline
Copy link

For something so basic, yeah... and Ionic fixed it... If everyone in this thread follows the webkit bug report, it might help it get attention.

@xtassin
Copy link
Author

xtassin commented Apr 14, 2020

I would humbly propose to use a fork I made some time ago. It's not really fresh but it includes the (imperfect) fix #45 to solve this problem. I will state it again: in my opinion, a specific CSS trick is not the answer to a rendering bug. I follow the webkit bug report.

@fmiguelroliveira
Copy link

Dear Felllows,

This is soooo stupid (not my fix, but the whole process)...

I solved the problem using document.body.offsetHeight.

After an enormous text alert created with all kind of document heights i found out that the wkview only returns the real size with the offsetheight...

hope this helps anyone, at least the ones who doesn't have a container inside body.

Nevertheless i'll keep my attention on bugtracking where i subscribed for news.

Saúde,
Miguel

@louisameline
Copy link

Body offset height won't work when your content is smaller than the window height. And there can be dependencies that use window.innerHeight, so in my case I really had to "fix" innerHeight with the 100vh trick. Otherwise I would have used a fork of Cordova as suggested by @xtassin

@fmiguelroliveira
Copy link

This is my css parameters:

`html, body {
height: 100vh;
min-height: 100vh;
}

html {
position: relative;
}

body {
margin: 0;
padding: 0;
overflow-x: hidden;
}`

@obxyann
Copy link

obxyann commented Jun 17, 2020

Confirm xtassin and louisameline's comment set viewport-fit=cover and height: 100vh only worked at startup but later when I use to compute the window height to program my layout dynamically it still go wrong. xtassin's comment do solve this problem.

@yellaiahd
Copy link

yellaiahd commented Oct 1, 2020

install cordova plugin add cordova-plugin-statusbar (check api for more information cordova-plugin-statusbar) and add below preferences in config.
preference name="StatusBarOverlaysWebView" value="false"
preference name="StatusBarBackgroundColor" value="#000000"
preference name="StatusBarStyle" value="lightcontent"

Lindsay-Needs-Sleep added a commit to miloproductionsinc/cordova-plugin-ionic-webview that referenced this issue Nov 5, 2020
This denies users control.
- Remove both methods that force "UIScrollViewContentInsetAdjustmentNever".
- See @dpogue's comments for reasoning: apache/cordova-plugin-wkwebview-engine#108
- Added some documentation that helps users configure their view properly for devices that have safe-insets due to "the notch" like iPhone X.  (So that they can acheive the same behavior as this change was doing if desired).
See PR ionic-team#531 for details
@Pietfro
Copy link

Pietfro commented Jan 17, 2021

For anyone that is still struggling with the viewport sizing on iOS, here is the best working solution, at least in my case:

html,
body {
    height: 100%;
    width: 100%;
    max-height: calc(100vh - env(safe-area-inset-bottom, 0px) - env(safe-area-inset-top, 0px));
    margin: 0;
    padding: 0;
    position: relative;
    overflow: hidden;
}

@raphaelarias
Copy link

I fixed this problem by adding a splash screen.

@terreng
Copy link

terreng commented Aug 3, 2021

For anyone reading over all this, wading through different answers: reapplying #45 is the real solution here.

Add [wkWebView.scrollView setContentInsetAdjustmentBehavior:UIScrollViewContentInsetAdjustmentNever]; before wkWebView.UIDelegate = self.uiDelegate; in CDVWebViewEngine.m

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

No branches or pull requests