130

I tested my Cordova-based app yesterday on the iPhone X Simulator in Xcode 9.0 (9A235) and it didn't look good. Firstly, instead of filling the full screen area, there was a black area above and below the app content. And worse, between the app content and the black was two white bars.

Adding cordova-plugin-wkwebview-engine so Cordova renders using WKWebView (not UIWebView) fixes the white bars. By my app is not migrated from UIWebView to WKWebView due to performance and memory leak issues when using cordova-plugin-wkwebview-engine which occur when loading images downloaded from Inapp Purchase hosted content into an HTML5 canvas (direct file:// access by the Webview is not possible due to security restrictions in WKWebView so the image data must be loaded via cordova-plugin-file).

These screenshots show a test app with a blue background set on the <body>. Above and below UIWebView, you can see the white bars, but not with WKWebView:


(source: pbrd.co)


(source: pbrd.co)

Both Cordova Webviews exhibit the black areas when compared to a native app which fills the full screen area:

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
DaveAlden
  • 30,083
  • 11
  • 93
  • 155
  • Interesting with wkwebview. In my game, i had it not full width, but also offset from center. In uiwebview it kept the same size, but centers itself at least. – agmcleod Oct 27 '17 at 03:21
  • I had this problem too so i made some workaround with just css see https://pt.stackoverflow.com/a/263460/55076 – Igor Trindade Dec 16 '17 at 15:56
  • I am having this problem too. Just adding the `` tag to my cordova index.hml file as others listed below is not working. I am running Cordova 7x with cordova-ios 4.5.4 - is there anything else I need to be doing? – rolinger Feb 15 '18 at 16:20

9 Answers9

260

I found the solution to the white bars here:

Set viewport-fit=cover on the viewport <meta> tag, i.e.:

<meta name="viewport" content="initial-scale=1, width=device-width, height=device-height, viewport-fit=cover">

The white bars in UIWebView then disappear:

The solution to remove the black areas (provided by @dpogue in a comment below) is to use LaunchStoryboard images with cordova-plugin-splashscreen to replace the legacy launch images, used by Cordova by default. To do so, add the following to the iOS platform in config.xml:

<platform name="ios">    
    <splash src="res/screen/ios/Default@2x~iphone~anyany.png" />
    <splash src="res/screen/ios/Default@2x~iphone~comany.png" />
    <splash src="res/screen/ios/Default@2x~iphone~comcom.png" />
    <splash src="res/screen/ios/Default@3x~iphone~anyany.png" />
    <splash src="res/screen/ios/Default@3x~iphone~anycom.png" />
    <splash src="res/screen/ios/Default@3x~iphone~comany.png" />
    <splash src="res/screen/ios/Default@2x~ipad~anyany.png" />
    <splash src="res/screen/ios/Default@2x~ipad~comany.png" />   

    <!-- more iOS config... -->
</platform>

Then create the images with the following dimensions in res/screen/ios (remove any existing ones):

Default@2x~iphone~anyany.png - 1334x1334
Default@2x~iphone~comany.png - 750x1334
Default@2x~iphone~comcom.png - 1334x750
Default@3x~iphone~anyany.png - 2208x2208
Default@3x~iphone~anycom.png - 2208x1242
Default@3x~iphone~comany.png - 1242x2208
Default@2x~ipad~anyany.png - 2732x2732
Default@2x~ipad~comany.png - 1278x2732

Once the black bars are removed, there's another thing that's different about the iPhone X to address: The status bar is larger than 20px due to the "notch", which means any content at the far top of your Cordova app will be obscured by it:

Rather than hard-coding a padding in pixels, you can handle this automatically in CSS using the new safe-area-inset-* constants in iOS 11.

Note: in iOS 11.0 the function to handle these constants was called constant() but in iOS 11.2 Apple renamed it to env() (see here), therefore to cover both cases you need to overload the CSS rule with both and rely on the CSS fallback mechanism to apply the appropriate one:

body{
    padding-top: constant(safe-area-inset-top);
    padding-top: env(safe-area-inset-top);
}

The result is then as desired: the app content covers the full screen, but is not obscured by the "notch":

I've created a Cordova test project which illustrates the above steps: webview-test.zip

Notes:

Footer buttons

  • If your app has footer buttons (as mine does), you will also need to apply safe-area-inset-bottom to avoid them being overlapped by the virtual Home button on iPhone X.
  • In my case, I couldn't apply this to <body> as the footer is absolutely positioned, so I needed to apply it directly to the footer:

.toolbar-footer{
    margin-bottom: constant(safe-area-inset-bottom);
    margin-bottom: env(safe-area-inset-bottom);
}

cordova-plugin-statusbar

  • The status bar size has changed on iPhone X, so older versions of cordova-plugin-statusbar display incorrectly on iPhone X
  • Mike Hartington has created this pull request which applies the necessary changes.
  • This was merged into the cordova-plugin-statusbar@2.3.0 release, so make sure you're using at least this version to apply to safe-area-insets

splashscreen

  • The LaunchScreen storyboard constraints changed on iOS 11/iPhone X, meaning the splashscreen appeared to "jump" on launch when using existing versions of the plugin (see here).
  • This was captured in bug report CB-13505, fixed PR cordova-ios#354 and released in cordova-ios@4.5.4, so make sure you're using a recent version of the cordova-ios platform.

device orientation

  • When using UIWebView on iOS 11.0, rotating from portrait > landscape > portrait causes the safe-area-inset not to be re-applied, causing the content to be obscured by the notch again (as highlighted by jms in a comment below).
  • Also happens if app is launched in landscape then rotated to portrait
  • This doesn't happen when using WKWebView via cordova-plugin-wkwebview-engine.
  • Radar report: http://www.openradar.me/radar?id=5035192880201728
  • Update: this appears to have been fixed in iOS 11.1

For reference, this is the original Cordova issue I opened which captures this: https://issues.apache.org/jira/browse/CB-13273

DaveAlden
  • 30,083
  • 11
  • 93
  • 155
  • I added a comment to the Cordova issue, but for anyone finding this here: To remove the black bars and take the full screen height, you must use a LaunchStoryboard instead of splash screen images. This is supported by newer versions of Cordova: https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-splashscreen/index.html#launch-storyboard-images – dpogue Sep 15 '17 at 06:26
  • @dpogue thanks, I've tried this and it works: will update the answer to include it – DaveAlden Sep 15 '17 at 08:32
  • 3
    Do you have any issues when you rotate the screen? I've been trying, but after rotate screen, everything is broken (safe-area-inset-* doesn't update their values depending device orientation; and after rotate portrait -> landscape -> portrait again, the initial values are broken too). Could it be some issue with apple/safari browser? – Juan Miguel S. Sep 19 '17 at 12:00
  • @jms I hadn't tested this (my affected production app is fixed in portrait) but yes, I can reproduce the issue in the above test app: rotating from portrait > landscape > portrait, the initial safe-inset value appears to be no longer applied. Will update my answer with a note on this. – DaveAlden Sep 19 '17 at 12:18
  • @DaveAlden thanks for checking it, at least it's not something happening just in my computer. Hope apple fixes it in final iOS 11 version... – Juan Miguel S. Sep 19 '17 at 16:09
  • To get rid of the black bars specifically, I had one splash screen that was called `Default@2x~universal~anyany.png` and I just had to rename `@2x` to `@3x`. My splash screen image is a 10x10 solid color, which is why this works I guess. But otherwise the list of different splash screens you specified is probably better. – Jespertheend Sep 24 '17 at 01:04
  • Not working for me: I add `viewport-fit=cover` on the viewport `` tag. After i delete `cordova-plugin-wkwebview-engine` plugin white space is gone .But I need this plugin in my app. My issue https://stackoverflow.com/questions/46494221/ionic-white-space-in-bottom-with-wkwebview-in-ios-11 – wstudiokiwi Oct 01 '17 at 06:14
  • @jms I've seen the same, created a Jira issue and pull request here: https://github.com/apache/cordova-plugin-statusbar/pull/88 – Dan Field Oct 04 '17 at 15:36
  • 1
    In my case, when I added `viewport-fit=cover` my whole app just shows a blank white screen and nothing else. I'm using iOS11, Xcode9 on iPhone 7 Plus. Anyone experiencing similar behavior? – Dimitri Oct 11 '17 at 14:35
  • Wanted to thank you for this solution as it seems to work fine, using your suggestion and using the modded version of status bar along with view port suggestion fixed this issue. The only issue i had was padding-top: constant(safe-area-inset-top); which didnt work unless i used margain-bottom which then threw all my other devices off, my suggestion for anyone having to use the same is dynamically detect if its an iphone X (height is 812px) load some extra css into the document which does as seen above only on the iphone X – Rlemm1991 Nov 02 '17 at 07:56
  • We've implemented these fixes which look fantastic in the emulator, but for some reason are failing on-device. We're applying specialized styles using device-detection (viewport height), which might not be reliable, it looks like. Trying to get access to a physical device. – Brent Nov 13 '17 at 21:03
  • @Brent if you (or anyone else) has access to a physical device, can you confirm which of the above fixes are not working. So far I've only been able to test on Simulator. – DaveAlden Nov 15 '17 at 08:49
  • 1
    @DaveAlden - it looks that in 11.2 beta+ they've dropped `constant` for `env` keyword -- see also: https://webkit.org/blog/7929/designing-websites-for-iphone-x/ – Brent Nov 15 '17 at 21:49
  • This only worked for me, once I switch to Ionic's WebView. https://github.com/apache/cordova-plugin-statusbar/pull/87#issuecomment-332250769 – kim3er Nov 27 '17 at 14:13
  • .element { margin-bottom: constant(safe-area-inset-bottom); margin-bottom: env(safe-area-inset-bottom); } doesn't work for me. On iOS 11.1, it just makes the margin-bottom 0. – Tom Kincaid Dec 21 '17 at 17:35
  • 1
    where do you put the body css code in your App? Like in which file? Nothing works for me, I'm using Ionic 3. – Dimitri Dec 22 '17 at 18:28
  • 1
    Please note that that the app needs to be build with Cordova `cli-7.0.0` or higher! Took me a while to figure out that build.phonegap.com uses `cli-6.5.0` by default. – Sander Jan 16 '18 at 15:01
  • @Sander - Cordova 7x is required, but is there a base cordova-ios that is needed as well? – rolinger Feb 15 '18 at 12:32
  • For now I am only interested in fixing the white bars above and below. Is all that is needed is the `` tag in the header of the index.html file to do this? Because I added that and I am still getting the white bars. Not certain what to do now. I can tell my DIV is going further down behind the lower white bar because there is no border showing at the bottom and some text at the very bottom of the DIV isn't showing. So I know its there, but the white bar is covering it. – rolinger Feb 15 '18 at 12:35
  • But I have the blackbars NOT on a splashpage, so the solution to use the larger splash page images is not applicable. Its in my app itself, no splash image showing. – Laurence Cope May 21 '18 at 15:56
  • @DaveAlden After updating the splashscreens following your guide, my splashscreen configurations are ignored and the splashscreen is displaying only for a short time causing a white screen to be shown before the app is loaded. I've created a question but so far no one has the answer https://stackoverflow.com/questions/50951069/cordova-ios-splashscreen-configurations-ignored I hope you can help me with your experience. Thank you – Daniela Jun 27 '18 at 13:56
  • 1
    If you are using WKWebView and still facing bars at the bottom, set `body { height: 100vh; }`. – Thomas Jun 30 '18 at 07:51
  • I was wondering if this is backward compatible with older iPhones? So if i made this work for iPhone x what would happen if the app was installed on say iPhone 6? – Glen Elkins Jul 12 '18 at 12:19
  • @GlenElkins The value is 0 on older iPhones. – hvaughan3 Aug 31 '18 at 19:18
  • 2
    Is there any update regarding the rotation problem? I'm on iOS 12 and experiencing the same issue. Looks strange to me that this problem persists. /cc @jms – a--m Oct 09 '18 at 13:49
  • Is it possible to test it in xcode simulator? According to cordova-plugin-splashscreen docs "Simulator may not show expected images when launched from CLI ". I've tried, and in simulator black bars are still present. – Sergey Nikitin Oct 17 '18 at 09:32
  • I have an ionic app so I placed all the images in `resources/splash/ios` - if I create the `res/screen/ios` folder the images don't work. HOWEVER, it looks like its choosing the wrong image because the image isn't sized properly...it fills the whole screen and looks squished even with the outside edges of the image being cutoff. Any thoughts? – rolinger Aug 21 '19 at 16:51
  • now on a regular iPhone 6 (12.3) I get the same huge, over sized, skewed splash screen and then after a few seconds its shows the normal one. I then removed all new (above) splash screen references and files and its still happening. – rolinger Aug 21 '19 at 17:30
  • I got it all working however on the iPhone 6 its still showing a cached splash screen image - that image doesn't even exist in the app anymore. I deleted the app, rebooted the phone, reinstalled the app but its still showing - after the wrong big/skewed one shows it then shows the correct image properly sized. I can't get rid of the cached one. – rolinger Aug 21 '19 at 20:16
  • For anyone sharing my above issue or having issues on an Ionic app related to this, after compiling I found OLD splash screen files in this folder: `platforms/ios/myApp/Images/xcassets/LaunchImage.launchimage/` - also check the `LaunchStoryboard.imageset` folder and ensure all your images are correct. I found two files still showing the default cordova icon (Default-2436h.png and Default-Landscape-2436h.png) - I created two new image files of those Width/Height dimensions and copied over those two files. Everything is working now. – rolinger Aug 21 '19 at 20:46
  • Having White Space issue on Inner pages where i have no `ion-header` tags. it shows white space on top. but on other screens its working fine with header / background image. but not working without header tags. – Najam Us Saqib Oct 18 '19 at 09:54
  • @DaveAllen - This method no longer works for iOS 13....the upper menu tabs/status bar is pushed up behind the notch. – rolinger Jul 15 '20 at 21:36
38

For a manual fix to an existing cordova project

The black bars

Add this to your info.plist file. Fixing the launch image is a separate issue i.e. How to Add iPhoneX Launch Image

<key>UILaunchStoryboardName</key>
<string>CDVLaunchScreen</string>

The white bars

Set viewport-fit=cover in the meta tag

<meta name="viewport" content="initial-scale=1, width=device-width, height=device-height, viewport-fit=cover">
coder
  • 1,274
  • 1
  • 13
  • 19
  • Thanks! The .plist change has the same effect as the changes from the selected answer, but WAY faster. – 2Fwebd Dec 25 '17 at 15:49
  • What does each of these tasks do to CSS pixel height and width? My app has a series of narrow divs at the top (menus, etc)...and then I calculate the remaining pixel height to have the last DIV fill the rest of the screen. Right now I can see the lower white bar cover some of that DIV, but I can also tell not all of it - implying the DIV is still not going to the bottom of the screen. And in turn, my app starts below the upper white bar so its not even trying to use the upper space. – rolinger Feb 15 '18 at 12:41
  • I used `UILaunchStoryboardName` and it managed to remove the black bars. But my splash screen gets expanded. Any reason why? The accepted answer isn't working for me – Huiting May 10 '18 at 07:23
  • @coder Thanks - but adding the UILaunchStoryboardName to the plist stops me from being able to submit to the app store: ERROR ITMS-90705: "Launch storyboard not found. Make sure you specify the launch storyboard filename without a filename extension for the key UILaunchStoryboardName in the Info.plist." – Matt Roberts Jul 17 '18 at 15:24
  • @Huiting did you find any solution about your case? – LMaker Apr 04 '19 at 20:26
  • @LMaker since this was almost 1 yr ago, I cant really remember. But I think it was because the splash screen size was not yet catered for iPhone X. I believed I redid a new splashscreen with the required dimensions – Huiting Apr 07 '19 at 12:35
  • If I use this, I got the error "the bundle does not contain an app icon for ipad of exactly '167x167' pixels"... why? – Piero Alberto Jun 06 '19 at 11:52
  • All that always gets overwritten with the next ionic prepare command, UILaunchStoryboardName and it’s value CDVLaunchScreen is being removed by ionic prepare command. :( – David Jan 12 '21 at 08:44
18

There is 3 steps you have to do

for iOs 11 status bar & iPhone X header problems


1. Viewport fit cover

Add viewport-fit=cover to your viewport's meta in <header>

<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0,viewport-fit=cover">

Demo: https://jsfiddle.net/gq5pt509 (index.html)


  1. Add more splash images to your config.xml inside <platform name="ios">

Dont skip this step, this required for getting screen fit for iPhone X work

<splash src="your_path/Default@2x~ipad~anyany.png" />   <!-- 2732x2732 -->
<splash src="your_path/Default@2x~ipad~comany.png" />   <!-- 1278x2732 -->
<splash src="your_path/Default@2x~iphone~anyany.png" /> <!-- 1334x1334 -->
<splash src="your_path/Default@2x~iphone~comany.png" /> <!-- 750x1334  -->
<splash src="your_path/Default@2x~iphone~comcom.png" /> <!-- 1334x750  -->
<splash src="your_path/Default@3x~iphone~anyany.png" /> <!-- 2208x2208 -->
<splash src="your_path/Default@3x~iphone~anycom.png" /> <!-- 2208x1242 -->
<splash src="your_path/Default@3x~iphone~comany.png" /> <!-- 1242x2208 -->

Demo: https://jsfiddle.net/mmy885q4 (config.xml)


  1. Fix your style on CSS

Use safe-area-inset-left, safe-area-inset-right, safe-area-inset-top, or safe-area-inset-bottom

Example: (Use in your case!)

#header {
   position: fixed;
   top: 1.25rem; // iOs 10 or lower
   top: constant(safe-area-inset-top); // iOs 11
   top: env(safe-area-inset-top); // iOs 11+ (feature)

   // or use calc()
   top: calc(constant(safe-area-inset-top) + 1rem);
   top: env(constant(safe-area-inset-top) + 1rem);
  
   // or SCSS calc()
   $nav-height: 1.25rem;
   top: calc(constant(safe-area-inset-top) + #{$nav-height});
   top: calc(env(safe-area-inset-top) + #{$nav-height});
}

Bonus: You can add body class like is-android or is-ios on deviceready

var platformId = window.cordova.platformId;
if (platformId) {
   document.body.classList.add('is-' + platformId);
}

So you can do something like this on CSS

.is-ios #header {
 // Properties
}
Community
  • 1
  • 1
l2aelba
  • 21,591
  • 22
  • 102
  • 138
5

In my case where each splash screen was individually designed instead of autogenerated or laid out in a story board format, I had to stick with my Legacy Launch screen configuration and add portrait and landscape images to target iPhoneX 1125×2436 orientations to the config.xml like so:

<splash height="2436" src="resources/ios/splash/Default-2436h.png" width="1125" />
<splash height="1125" src="resources/ios/splash/Default-Landscape-2436h.png" width="2436" />

After adding these to config.xml ("viewport-fit=cover" was already set in index.hml) my app built with Ionic Pro fills the entire screen on iPhoneX devices.

TaeKwonJoe
  • 1,077
  • 11
  • 24
2

Just a note that the constant keyword use for safe-area margins has been updated to env for 11.2 beta+

https://webkit.org/blog/7929/designing-websites-for-iphone-x/

Brent
  • 111
  • 2
  • 9
2

Fix for iPhone X/XS screen rotation issue

On iPhone X/XS, a screen rotation will cause the header bar height to use an incorrect value, because the calculation of safe-area-inset-* was not reflecting the new values in time for UI refresh. This bug exists in UIWebView even in the latest iOS 12. A workaround is inserting a 1px top margin and then quickly reversing it, which will trigger safe-area-inset-* to be re-calculated immediately. A somewhat ugly fix but it works if you have to stay with UIWebView for one reason or another.

window.addEventListener("orientationchange", function() {
    var originalMarginTop = document.body.style.marginTop;
    document.body.style.marginTop = "1px";
    setTimeout(function () {
        document.body.style.marginTop = originalMarginTop;
    }, 100);
}, false);

The purpose of the code is to cause the document.body.style.marginTop to change slightly and then reverse it. It doesn't necessarily have to be "1px". You can pick a value that doesn't cause your UI to flicker but achieves its purpose.

YYL
  • 564
  • 4
  • 7
  • UIWebView was depricated in iOS8... I doubt if any of the existing bugs will be fixed. Apple is warning when uploading apps that this will be discontinued soon... thus time to take the pain and migrate to WKWebView... – Mozfet Jan 29 '20 at 11:21
2

I'm developing cordova apps for 2 years and I spent weeks to solve related problems (eg: webview scrolls when keyboard open). Here's a tested and proven solution for both ios and android

P.S.: I'm using iScroll for scrolling content

  1. Never use viewport-fit=cover at index.html's meta tag, leave the app stay out of statusbar. iOS will handle proper area for all iPhone variants.
  2. In XCode uncheck hide status bar and requires full screen and don't forget to select Launch Screen File as CDVLaunchScreen
  3. In config.xml set fullscreen as false
  4. Finally, (thanks to Eddy Verbruggen for great plugins) add his plugin cordova-plugin-webviewcolor to set statusbar and bottom area background color. This plugin will allow you to set any color you want.
  5. Add below to config.xml (first ff after x is opacity)

    <preference name="BackgroundColor" value="0xff088c90" />
    
  6. Handle your scroll position yourself by adding focus events to input elements

    iscrollObj.scrollToElement(elm, transitionduration ... etc)
    

For android, do the same but instead of cordova-plugin-webviewcolor, install cordova-plugin-statusbar and cordova-plugin-navigationbar-color

Here's a javascript code using those plugins to work on both ios and android:

function setStatusColor(colorCode) {
    //colorCode is smtg like '#427309';
    if (cordova.platformId == 'android') {
        StatusBar.backgroundColorByHexString(colorCode);
        NavigationBar.backgroundColorByHexString(colorCode);
    } else if (cordova.platformId == 'ios') {
        window.plugins.webviewcolor.change(colorCode);
    }
}
gdarcan
  • 595
  • 5
  • 8
2

Check out this link, sometimes may be helpful. I could solve the issue with the solution provided below. https://github.com/apache/cordova-plugin-wkwebview-engine/issues/108

Add

[wkWebView.scrollView setContentInsetAdjustmentBehavior:UIScrollViewContentInsetAdjustmentNever];

before wkWebView.UIDelegate = self.uiDelegate; in CDVWebViewEngine.m

Govind
  • 2,337
  • 33
  • 43
1

If you install newer versions of ionic globally you can run ionic cordova resources and it will generate all of the splashscreen images for you along with the correct sizes.

nebulr
  • 641
  • 6
  • 7