In the web development world we're used to a rapid pace of change - especially in mobile. As such, the variety of changes introduced in iOS7 are not surprising; rather, they represent yet another set of platform specific issues we need to address. One of these changes - the switch to a translucent status bar - has caused a serious issue for hybrid web applications.

For example consider this trivial app.

<!DOCTYPE html>
<html>
    <head>
        <title>My App</title>
        <meta charset="utf-8">
    </head>
    <body>
        Hello World
    </body>
</html>

When loaded as an application in iOS7 this displays as follows:

Issue with the status bar in iOS7. The text is cut off.

As you can see from the image above, iOS7 deployed Cordova applications use a translucent status bar that overlays the content by default. So what in the world do you do about this?

Meta Tags

If you're like me, your first thought was probably: doesn't iOS have meta tags to configure this?

And the answer is - it did. Since iOS 2.1 Apple supported a apple-mobile-web-app-status-bar-style <meta> tag to configure the status bar on the top of the screen. For example the following told iOS to use the traditional black status bar:

<meta name="apple-mobile-web-app-status-bar-style" content="black">

The valid values for the tag were black, black-translucent, and default (which was the same as black).

Unfortunately as of iOS7 these tags are no longer supported; including them has no effect on the status bar.

What's next?

Device Sniffing and Hacking

iOS7 has been out for awhile, and some people have come up with some clever workarounds. Shazron Abdullah (@shazron) from Adobe has a gist with the most widely accepted solution, summarized below.

function onDeviceReady() {
    if (parseFloat(window.device.version) >= 7.0) {
          document.body.style.marginTop = "20px";
          // OR do whatever layout you need here, to expand a navigation bar etc
    }
}

document.addEventListener('deviceready', onDeviceReady, false);

On device ready this checks whether device is running a version of 7.0 or greater, then adds a CSS margin-top to the <body> to compensate for the status bar. The image below shows that this does indeed fix the issue by bumping down the content.

Fixed version of the iOS status bar

I have a few minor issues with this solution. First, because it waits until deviceready, the CSS change is delayed and the user may see the shift. To get around this we can sniff the user agent instead of relying on Cordova's window.device API. Second, the solution only checks the device's version, and doesn't ensure that the device is actually running iOS. The code below shows my solution that addresses these two concerns:

<script>
    var updateStatusBar = navigator.userAgent.match(/iphone|ipad|ipod/i) &&
        parseInt(navigator.appVersion.match(/OS (\d)/)[1], 10) >= 7;

    if (updateStatusBar) {
        document.body.style.marginTop = '20px';
    }
</script>

This code first detects whether the app is running on an iOS device, then whether the version of iOS is 7 or greater. If so, the same margin-top workaround is applied. Because this version does not rely on deviceready, it is safe to place anywhere in the <body>.

One last note, if your application uses a fixed header this fix will not work. For example see the image below of a fixed header in jQuery Mobile.

Headers with fixed positioning still overlap the status bar

The header is styled using position: fixed; top: 0; therefore it appears at the top of the viewport regardless of the margin on the <body>.

One of the commenters on the original gist, provides an interesting solution for this - using webkit-transforms instead of margin. Below we show our workaround modified to use webkit-transform.

<script>
    var updateStatusBar = navigator.userAgent.match(/iphone|ipad|ipod/i) &&
        parseInt(navigator.appVersion.match(/OS (\d)/)[1], 10) >= 7;

    if (updateStatusBar) {
        document.body.style.webkitTransform = 'translate3d(0, 20px, 0)';
    }
</script>

This approach literally moves the entire viewport of the application underneath the status bar. Below shows the same jQuery Mobile application with this workaround applied.

Fixed version of the iOS status bar in jQuery Mobile

Of course, these JavaScript hacks are incredibly fragile. What happens if iOS8 radically changes status bars again? It would be far better if we could tie into the native platform, and thanks to Cordova, we can!

StatusBar Cordova Plugin

With iOS7 Apple introduced some native Objective C APIs to control the status bar. Because of Cordova, we have the ability to bridge these native APIs directly into JavaScript APIs. Luckily for us @shazron has already done this with the StatusBar plugin.

After adding the plugin to your application, you are given a StatusBar object with a number of methods to manipulate the status bar in JavaScript directly.

For example, to get iOS6 behavior back all we need to do is call the overlaysWebView method with false.

<script>       
    document.addEventListener('deviceready', function() {
        StatusBar.overlaysWebView(false);
    }, false);
</script>

Now our application uses an iOS6-like status bar that does not overlay the rest of the application, as shown below.

Display of the iOS6 like status bar

With native access all sorts of things are possible. You can hide the status bar using StatusBar.hide(), or even change its background color with StatusBar.backgroundColorByName() or StatusBar.backgroundColorByHexString(). For example the following sets the status bar to green.

<script>       
    document.addEventListener('deviceready', function() {
        StatusBar.overlaysWebView(false);
        StatusBar.backgroundColorByName('green');
    }, false);
</script>

Which displays as follows.

Display of the green iOS status bar

For more of what the StatusBar plugin makes possible, be sure to checkout its API.

Kendo UI Mobile

If you're a Kendo UI Mobile user you're in luck. As part of its complete iOS7 support Kendo UI Mobile includes a solution for this problem - seamless status bars. An example of this is shown below.

<!DOCTYPE html>
<html>
<head>
    <title>My App</title>
    <meta charset="utf-8">

    <link href="kendo.mobile.all.css" rel="stylesheet">
    <style>
        .km-on-ios .km-header .km-navbar {
            background-color: skyblue;
        }
        .km-on-ios .km-header .km-widget,
        .km-on-ios .km-header .km-view-title {
            color: white;
        }
    </style>

    <script src="jquery.js"></script>
    <script src="kendo.mobile.js"></script>
</head>
<body>
    <div data-role="view" data-title="Header">
        <header data-role="header">
            <div data-role="navbar">
                <div data-role="view-title"></div>
            </div>
        </header>
        Hello World
    </div>

    <script>
        new kendo.mobile.Application($(document.body), {
            statusBarStyle: "black-translucent"
        });
    </script>
</body>
</html>

Internally Kendo UI Mobile detects whether the application is running in iOS7, and if so, compensates for the status bar in the layout automatically. The nice thing about this approach is you don't have to worry about manually testing this behavior or worry about maintaining it in the future; Kendo UI Mobile takes care of that for you. The display of the above example is shown below.

Display of Kendo UI Mobile's Solution

Outstanding Issues

While the web has come up with workarounds for most of the iOS7 status bar issues, there are still a few that remain unresolved.

  • The status bar still overlays content displayed in a cordova InAppBrowser. There is no known workaround, but a fix is slated for cordova 3.2.
  • The StatusBar plugin does not work in apps that lock the device into landscape mode.

If you are aware of workarounds for any of these problems, please let us know in the comments. If we run across anything we'll make sure to update this post.

Wrapping Up

Apple's decision to make the status bar overlay Cordova hybrid web applications has created another fun challenge for web developers. While no workaround is elegant, you can workaround the problem using a JavaScript hack, a Cordova plugin, or a framework such as Kendo UI Mobile.

For more on this problem you can checkout our status bar docs. If you have any other questions about the status bar in iOS7, let us know in the comments.

About the Author

TJ VanToll

is a web developer, speaker, and writer living in Lansing, MI and working as a developer advocate for Telerik. He is an open source advocate that is on the jQuery UI team and publishes his blog open source. TJ is also the author of an upcoming book from ManningjQuery UI in Action. When not online, TJ is generally found chasing his twin sons in circles. TJ is @tjvantoll on Twitter and tjvantoll on Github.

Related Posts

Comments

Comments are disabled in preview mode.