Ionic-framework: No padding for statusbar (on iOS) when nav-pushing inside a modal

Created on 21 Sep 2016  ·  45Comments  ·  Source: ionic-team/ionic-framework

Short description of the problem:

The navbar can overlap the statusbar on iOS, when a new page is pushed using NavController#push from inside of a modal. See screenshot.

img_2079

What behavior are you expecting?

Like all other navbars, this one should leave enough space for the statusbar.

Steps to reproduce:

  1. Open a modal.
  2. Within the modal, call NavController#push with any page.

Which Ionic Version? 2

Repo that shows an example of your issue

https://github.com/zmbc/statusbar

Go to the list, open an item, then hit "Push Something".

Run ionic info from terminal/cmd prompt: (paste output below)
Gulp version: CLI version 3.9.1
Gulp local: Local version 3.9.1
Ionic Framework Version: 2.0.0-beta.11
Ionic CLI Version: 2.0.0-beta.32
Ionic App Lib Version: 2.0.0-beta.18
ios-deploy version: 1.8.6
ios-sim version: 3.1.1
OS: Mac OS X El Capitan
Node Version: v6.3.0
Xcode version: Xcode 7.3.1 Build version 7D1014

Most helpful comment

Still present in ionic-angular 3.3.0. Any way to fix it?

All 45 comments

same issue here. i solved it by not pushing the new page but presenting it as a second modal.

Hello all! Thanks for using Ionic!. I am happy to report that I can no longer reproduce this issue with RC0. Thanks!

This bug still exists. This issue can only be reproduced on an actual device/emulator. It won't appear on desktop browsers unless you pass { statusbarPadding: true } to the config variable of IonicModule.forRoot(MyApp, config). I've created a quick repo to demonstrate this issue with RC0 https://github.com/msalcala11/modal-padding-bug.

Same issue here.

Can confirm this issue as well

yes this issue still exists. please reopen

We have to document modals better, we have people working on this right now.
@comfortme @royipressburger @CyrisXD @msalcala11 @zmbc You have to create a new ion-nav in order to have navigation inside a modal, just like you do to have navigation in your app.

@Component({
  template: '<ion-nav [root]="root"></ion-nav>'
})
export class NavigationModal {
  root = ModalFirstPage;
}

// YOUR CONTENT MODAL
@Component({})
export class ModalFirstPage {
}

(...)

  presentModalChildNav() {
    this.modalCtrl.create(NavigationModal).present();
  }

this still doesn't really make sense to me.

I have a page that I will navigate to either from another page OR from a modal depending on where the user is in the app.

When I do a nav.push within the modal it goes to the page, everything transitions nice and works exactly as I want it to. EXCEPT that the statusbar padding does not get applied when I navigate to the page from a modal.

I don't really see how the code snippet above helps me with that at all? This seems like it should be a really simple thing as functionally everything is working AND in one of the earlier betas the statusbar padding was also correctly applied but this was then broken again in a later release.

Note that android does not have any issue with the same code the navigating either from another page or from a modal all is formatted correctly and works just fine, I would expect ios to be the same.

Still exists. Any simple hacks to prevent this?

Apply the following CSS to ion-navbar and ion-title to fix this. I use an ngIf* to only apply it if the platform.is(iOS) as android doesn't need this. This is simply overridden by the default css when opening from another page on iOS so no issues there either.

Also note that any alert / actionsheet / pop over you open from the newly pushed page will open behind the page. You will need to hack the z-index value for those components to be higher than the modal z-index so they are always on top. Given that those things should always be ontop anyway that isn't really an issue.

<ion-navbar *ngIf="globals.isIos" style="height:calc(44px + 20px); min-height:calc(44px + 20px); padding-top:20px;">
    <button ion-button menuToggle>
      <ion-icon name="menu"></ion-icon>
    </button>
    <ion-title style="padding-top:14px !important;">{{selectedItem.name}}</ion-title>
  </ion-navbar>

Still having this issue. Will this be fixed soon?

@mrhirsch There's a similar issue on here. Check it out. It's not fixed, but @manucorporat asked for a repo example that I provided there so hopefully they're working on it.

@ghenry22

The way you're doing that padding is not a good way. Do not use *ngIf to hide navbars based on platform types. The calculation for the ion-content subsequently will not take account of the navbar and will cause the entire ion-content to shift up.

Instead, in the app.scss, add the following CSS.

.platform-ios .ios-header {
  height:calc(56px + 20px);
  min-height:calc(56px + 20px);
  padding-top:20px;
}

Then simply in the header that you need this (for me, it's all the pages where I push onto the Tab page), just add class="ios-header".

<ion-header>
  <ion-navbar class="ios-header">
  </ion-navbar>
</ion-header>

Much DRYer, and without the ion-content issue. Of course, if the Ionic Team looked into this themselves we wouldn't have to go through this pain.

For anyone who is stumbling on this with a popover, this is the same issue.

Regarding the solution: it's not a good idea to go with the CSS-fix approach because you are just masking something that you aren't doing as designed (even if it's a bit of a weird design tbh).

An other solution than the one manucorporat points out is to work with events. I did it like that and it's very simple and clean. Just fire an event in your modal or popover page and listen for it in your "parrent"-page. More on events can be found here: https://ionicframework.com/docs/api/util/Events/

@timvandijck Can you provide an example?

@kabus202 this is an example with a popover:

The page where you are launching the popover:

@Component({
    selector: 'page-my-page',
    templateUrl: 'my-page.html'
})
export class MyPage {
    popover = null;

    constructor(public navCtrl:NavController, public popoverCtrl: PopoverController, public events: Events) {
        this.events.subscribe('nav:my-other-page', () => {
            this.navCtrl.setRoot(MyOtherPage);

            if (this.popover) {
                this.popover.dismiss();
            }
        })
    }

    toggleActionsMenu(event) {
        this.popover = this.popoverCtrl.create(PopoverContentPage);
        this.popover.present({
            ev: event
        });
    }
}

The page that contains the content of the popover:

@Component({
    selector: 'page-popover-content',
    templateUrl: 'popover-content.html'
})
export class PopoverContentPage {

    constructor(public events: Events) {
    }

    registerAppliance() {
        this.events.publish('nav:my-other-page');
    }
}

Yeah, this is still an issue. Also, when you try to swipe to go back, it can sometimes act up and pop the view under the modal. @jgw96

Still present in ionic-angular 3.3.0. Any way to fix it?

@manucorporat Could you please reopen this issue? Open modal in page open by navController.push() cause same situation as pictured in first post.

Yep please re-open

@vosecek The issue exists, but you can use my css fix that I posted above. It works with 3.3.

Hey guys, check out the NavController api, specifically the section titled Navigating from an Overlay Component (pasted below)

Note the use of this.appCtrl.getRootNav(). This worked very well for me, so I'm curious if using App fixes this issue for others. Anyways, just thought y'all should know about this.

Navigating from an Overlay Component

import { Component } from '@angular/core';
import { App, ViewController } from 'ionic-angular';

@Component({
    template: `
    <ion-content>
      <h1>My PopoverPage</h1>
      <button ion-button (click)="pushPage()">Call pushPage</button>
     </ion-content>
    `
  })
  class PopoverPage {
    constructor(
      public viewCtrl: ViewController
      public appCtrl: App
    ) {}

    pushPage() {
      this.viewCtrl.dismiss();
      this.appCtrl.getRootNav().push(SecondPage);
    }
  }

I guess the question is why would you add so much over head when you can just nav.push and everything works completely fine except a bit of CSS that no one seems interested in fixing?

It kind of reminds me of Apples "just hold it differently" response to antenna issues.

Why this issue is closed if it still there?

@edwinchoate this works but not when you still need the popover to be active when you go back from the page. I don't think it's possible to navigate away and back to a popover like a normal page with the current design, the popover is positioned on a higher layer than all normal pages, so dismiss is required. Unless they change the behavior of popover altogether.

Since this bug hasn't been fixed, I've added this SCSS code as workaround and it worked for me. I hope it is usefull for you:

.toolbar-ios {
  height: 44px + $cordova-ios-statusbar-padding;
  padding-top: $cordova-ios-statusbar-padding;
}

.toolbar-title-ios {
  padding-top: $cordova-ios-statusbar-padding;
}

To all the people still stumbling over this. @manucorporat already presented the right idea. The code just has an error and is somewhat incomplete. I've tested this with Ionic 3.6.0.

In the content page that you present as a modal simply include another wrapper page class with a nav element like this:

@Component({
    template: '<ion-nav [root]="this.rootPage" [rootParams]="this.rootParams"></ion-nav>'
})
export class MyModalWrapper {
    private rootPage = MyModalContentPage;
    private rootParams;
    constructor(navParams: NavParams, private viewCtrl: ViewController) {
        this.rootParams = navParams;
        this.rootParams["data"]["closeModal"] = this.onCloseModal
    }
    onCloseModal = () => {
        this.viewCtrl.dismiss();
    }
}

And then modify your content page class like this:

@Component({ /* ... */ })
export class MyModalContentPage {
    /* ... */
    private closeModal;
    constructor(navParams: NavParams, /* ... */) {
        this.closeModal = navParams.get("closeModal");
    }
    /* ... */
}

Now you can call closeModallike a normal function in your class or template.

Now all that's left to do is replace MyModalContentPage with MyModalWrapper wherever you create and present the modal. So instead of:

this.modalCtrl.create(MyModalContentPage, { /* ... */ }).present();

do this:

this.modalCtrl.create(MyModalWrapper, { /* ... */ }).present();

Hope this helps.

@codemusings I did it this way:

@Component({
  template: '<ion-nav [root]="root" [rootParams]="params"></ion-nav>'
})
export class MyModalWrapper {
  root = MyModalContentPage;
  params: any;

  constructor(
    public navParams: NavParams,
    viewCtrl: ViewController,
  ) {
    this.params = Object.assign({}, navParams.data, {viewCtrl: viewCtrl});
  }
}

@Component({ /* ... */ })
export class MyModalContentPage {
    /* ... */
    private viewCtrl: ViewController;
    constructor(navParams: NavParams, /* ... */) {
        this.viewCtrl = navParams.get('viewCtrl');
    }
    /* ... */
    someFunc() {
      this.viewCtrl.dismiss();
    }
}

By passing in the whole ViewController you can use the same this.viewCtrl.dismiss() you would normally use; no changes in the content page are necessary except in the constructor.

I'm on Ionic 3.3.0 but I'm guessing it would work on the latest as well.

But the thing is, functionally it works completely fine as is and there is no need for all that extra code, just a single line CSS fix for iOS only and this isn't even an issue.

@ghenry22 That's not entirely correct for large screens, e.g. iPad, where the pushed page is fullscreen even though the modal is small.

I wish nav.push inside a modal Just Worked. But I'd rather do it this more complex way than rely on hackier CSS fixes.

@ghenry22 @zmbc The nav-view implies a separate nav stack, which you create when opening a modal. This is "the way".

When you call navCtrl.pop, it may create inadvertent issues with the root nav, since Ionic doesn't understand when you're in a modal and when you aren't.

I don't have any problem with pushed pages on iOS either? I mean I'll test it again now that you've mentioned it to make sure but they stay within the bounds of the modal for me.

Basically if I push or pop a page from within a modal I expect it to load and be bound within the modal.

If I push or pop on a normal page I expect it to load with normal full screen page.

I have pages that I can use in either scenario so adding code to handle one scenario can cause issues in the other.

If you want the pushed page inside a modal to open full screen on ipad then I Guess you would have to have a function that closes the modal and then pushes the page which could get a bit messy for sure.

@wbhob this may be the desired outcome but all you have to do is look at this ticket and the ionic forums and stack overflow to see the same question being asked again and again.

So obviously it is an issue from a pure usability point of view for people. It would be great if ionic could implement something under the hood so that it "just worked" then all the comments and requests on this closed issue would stop :)

Made a PR to the docs @ghenry22

My pr was merged! Check the modal docs

@jgw96 I am hoping this will be resolved with Ionic4. It has been outstanding since ionic2 RC0 with no action which is a bit shocking considering it's a simple CSS fix and then using navigation just works as expected whether you are in a modal or regular page. As it should.

It works as expected, it's not an issue. There are details on doing this in the Ionic docs (I wrote that part of the docs)

@wbhob except it doesn’t work as expected. As shown by the numerous threads on the forum. Issues here and on stack overflow.

Navigation works exactly as you would expect it to with the exception that the pushed page loses its status at padding. This is a simple css fix and does not require anything more complicated.

Your recommended work around and others involve closing the overlay before opening the new page. This is not a feasible approach for my app as I want the user to be able to view some information either from a modal OR from other regular pages and if viewing from a modal I want them to be able to go back to the modal.

Anyway I posted a css only fix for this into one of the other issues logged for this the other day which completely resolved it for me by simply applying the standard ionic page styles as they would be in a non-modal setting.

The proper way of doing this is to make a self-contained navigation instance inside of the modal. Your intent is to navigate to additional pages, but when you call navCtrl.push it, as you would expect, runs it against the root nav stack since it doesn't know any better. When you do it properly and make a nav stack exclusive to the modal, it functions correctly.

Yes that is a way of doing it for a specific scenario. Assuming that in your use case you want to dismiss the overlay that is open (modal/pop over etc) and THEN open the the page. In this scenario, yes what you have said and what is shown in the Ionic component docs for nav controller works fine.

I do not want to dismiss the modal that is open, I want to be able to navigate to a page which will show some additional information, and when done click BACK to go back to the modal where the page was opened from. This scenario is not covered by the docs you refer to.

For the second scenario everything works perfectly in terms of functionality. Everything works with no issue at all on Android. The only issue is that on IOS only the correct css class is not applied to the pushed page when it is pushed from an overlay. There is a simple CSS fix for this.

Just stick the follow into your app.scss and you're all good to go as the correct class will now be applied to pages whether they are pushed from a modal or another regular page.

Now both scenarios work well.
1) when you want to dismiss the overlay and load a new page use the method in the navcontroller docs.
2) when you don't want to dismiss the overlay and load a new page which can go BACK and still have the source overlay available just include the css below and it resolves the layout issue.

// handle top padding disappearing in modals
@media only screen and (max-width: 767px){
    .ios > .ion-page > ion-header > .toolbar.statusbar-padding:first-child {
        padding-top: calc(20px + 4px);
        padding-top: calc(constant(safe-area-inset-top) + 4px);
        padding-top: calc(env(safe-area-inset-top) + 4px);
        min-height: calc(44px + 20px);
        min-height: calc(44px + constant(safe-area-inset-top));
        min-height: calc(44px + env(safe-area-inset-top));
        }
}

@ghenry22 I think you're mistaken. I am using the recommended solution in an Ionic application, and the modal is not dismissed. It pushes a new page onto the modal stack, and when the user taps "Back" they return to the modal.

I think your app probably has some sort of bug if you are not seeing that behavior with the recommended solution. If I were you, I'd open a StackOverflow question to try to debug it. Someone there could help you figure it out.

This issue isn't the right place, because this functionality is already in Ionic and has been adequately documented for general use.

@zmbc https://ionicframework.com/docs/api/navigation/NavController/
The docs here for navigating from an overlay show dismiss() being called before navigating to the next page. This is what I was referring to.

Digging through the old PR logs it seems that the updates added by @wbhob are not reflected on the ionic component documentation pages. I'll try the solution from the old commits but if it works as you say it would be good to get that info included in the nav controller component API docs or examples so it's actually able to be found easily.

Still if the correct CSS classes are applied (as on Android) then there is no need for any work around or additional code from the user, surely this would be a desirable outcome?

@ghenry22 I'm not sure where the documentation lives in the project anymore, but I think you're correct that @wbhob's changes are no longer there (although they would be in ModalController, not NavController).

As I've explained before, it is simply not true that the CSS fix is just as good as the recommended solution. It is only equivalent on small screens where modals are full-screen, and who knows whether it will work in the next version of Ionic? The recommended solution creates a true navigation stack, which is what you want in this situation, works on all screen sizes, and uses a documented public API. It also isn't a big difference in code complexity: I would much rather have a few more lines of boilerplate than some obscure SCSS I won't be able to understand in the future.

I recommend you use this approach to do exactly what you want: push a page on a modal and have the ability to go back to the modal. If you don't want to do that, it's up to you. But this is pretty clearly not an issue with Ionic.

@zmbc the documentation would be on the navController as that is what is used for navigation. The ModalControl merely creates and presents the modal.

I'd disagree that the CSS is obscure, it's the standard ionic CSS that is applied to a page when pushed normally, I do agree that it could stop working or cause issues if there is a major change to ionic (such as with V4 coming) which is why this should be fixed as a bug that affects the iOS platform for Ionic so people don't NEED to apply any fix.

This issue does not exist on Android, which works perfectly without any changes. So this does appear to be a platform specific bug with ionic applying CSS classes.

I admit I haven't tested it on a larger screen device yet and there may be something else needed there, I will look at that.

I can see that there is a solution which has been lost from the docs and now exists only as a comment in the header of a source file. If this solution can be restored to the official nav controller docs, into the section on navigating from a Modal, then at least there is a solution that is documented and the documentation is easily accessible to people reading the Ionic Docs.

We're clearly not going to agree on which approach is right or wrong, so putting that aside, as long as there is an officially recommended way to do this (whatever it is) properly added to the docs then that's good enough for me.

Thanks for the issue! This issue is being locked to prevent comments that are not relevant to the original issue. If this is still an issue with the latest version of Ionic, please create a new issue and ensure the template is fully filled out.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

daveshirman picture daveshirman  ·  3Comments

alan-agius4 picture alan-agius4  ·  3Comments

BilelKrichen picture BilelKrichen  ·  3Comments

GeorgeAnanthSoosai picture GeorgeAnanthSoosai  ·  3Comments

gio82 picture gio82  ·  3Comments