DEV Community

Cover image for Display your PWA / website fullscreen
Manuel Sommerhalder
Manuel Sommerhalder

Posted on • Updated on

Display your PWA / website fullscreen

In this short article I will show you how to expand your installed PWA to the full edge of the screen of a mobile device and how to take care of design issues that might occur.

Standalone mode

As soon as the user has added your PWA to the home screen and opened it, it runs in a standalone mode, where e.g. the navigation bar of the browser will disappear and we can produce more app-like designs.

We can detect if the PWA is running in standalone mode inside our application like this:

// on iOS Safari
window.navigator.standalone

// on Android Chrome
window.matchMedia(
  '(display-mode: standalone)'
).matches
Enter fullscreen mode Exit fullscreen mode

Because of the platform difference, a more popular approach is to define a start_url inside your manifest.json file, where we can add a parameter that will be added, when the app is started in standalone mode. Then we can check for the parameter inside our application to make changes to our UI.

To display it fullscreen and remove native control elements, we also have to add the display property with the value standalone (fullscreen won't work). Here's our current manifest:

// manifest.json
{
  "name": "Example App",
  "display": "standalone",
  "start_url": "/?standalone=true"
}
Enter fullscreen mode Exit fullscreen mode

Meta Tags

To display your app fullscreen, we will also have to add a few meta tags.

You might already have a viewport meta tag, but make sure viewport-fit=cover is inside it (separated by ;):

<meta name="viewport"
    content="width=device-width; initial-scale=1; viewport-fit=cover">
Enter fullscreen mode Exit fullscreen mode

Then we have to add the mobile-web-app-capable and status-bar-style meta tags:

<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">

<!-- possible content values: default, black or black-translucent -->
<meta name="apple-mobile-web-app-status-bar-style"
    content="black-translucent">
Enter fullscreen mode Exit fullscreen mode

Note that we can decide, whether the status bar should have a white (default), black or transparent (with white color) background. Take into account that this meta tag is only used when the app starts, so it's app-wide and we can't modify the meta tag later to change the color dynamically.

Because we also want to be able to display content underneath the status bar, we'll use the transparent background (black-translucent). This will also shift our app up to the top of the screen.

Now we can produce fancy headers that look like this:

Alt Text

Safe Area

Since we can display content underneath the status bar now, we'll have to make sure that the white text will always be readable (e.g. with a decorative shadow or ensuring dark background colors) and that there will be no interactive elements underneath. Also we might have to take the notch into account, which some newer iOS versions have:

Alt Text

To solve those problems we can utilize the safe-area CSS env variables (supported since iOS >= 11.1 and Chrome >= 69):

.element {
    height: env(safe-area-inset-top);
    width: env(safe-area-inset-left);
    margin: env(safe-area-inset-right);
    // you can also use fallback values
    padding: env(safe-area-inset-bottom, 20px);
}
Enter fullscreen mode Exit fullscreen mode

As an example, I implemented a sticky navigation bar vue component for my app, which has an element with the top safe-area applied as height. It will be transparent as long as the transparent property is true and the user has not scrolled down. Here's the crucial part of the component:

<!-- NavigationBar.vue -->
<div class="sticky top-0">
    <div
        class="h-safe-area-inset-top"
        :class="{
            'bg-black': !transparent
                        || (transparent && scrollTop > 0)
        }"
    ></div>
    ...
</div>

<style>
.h-safe-area-inset-top { height: env(safe-area-inset-top); }
.bg-black { background-color: #444; }
</style>

<script>
export default {
  data() {
    return {
      scrollTop: 0
    }
  },
  props: {
    transparent: {
      type: Boolean,
      default: false
    }
  },
  methods: {
    scrollListener(e) {
      this.scrollTop = e.target.scrollTop;
    }
  },
  mounted() {
    window.addEventListener('scroll', this.scrollListener);
  }
}
</script>
Enter fullscreen mode Exit fullscreen mode

If you have a question, don't hesitate to leave a comment. Happy coding and designing! 👨🏼‍💻

Top comments (8)

Collapse
 
lohit9 profile image
Lohit Talasila • Edited

Thanks for the write up, however this doesn't seem to work in the latest iOS version (14.5). Was wondering if anyone is having this issue or if I'm missing something. Any insight would be appreciate, thanks!

Collapse
 
oncode profile image
Manuel Sommerhalder

Which part exactly doesn't work? The black-translucent status bar?

Collapse
 
lohit9 profile image
Lohit Talasila

No, referenced firt.dev/ios-14.5/ and ended up using dark-content for the status bar. The issues I am having are:

  1. Unable to achieve the desire full screen view
  2. The width seems to be reduced and the height is retained, thereby affecting existing styles.
Collapse
 
majklzumberi profile image
majkl zumberi

That's very helpfull! Thanks!

Collapse
 
havincy profile image
haVincy

Seems black-translucent now is deprecated in iOS 14.5. Refer : t.co/vE0aBdWKKs?amp=1
Are you able to enable it < 14.5?

Collapse
 
oncode profile image
Manuel Sommerhalder • Edited

Deprecated hopefully doesn't mean removed, but can't test it right now. But like your linked article says, it seems like a half baked solution, since there has been no alternative value introduced for black-translucent and there are three values for the same.

Collapse
 
benlune profile image
Benoît Plâtre

Thank you for your post !
This works both for Android and IOS (tested on IOS 14)

window.matchMedia(
'(display-mode: standalone)'
).matches

Collapse
 
oncode profile image
Manuel Sommerhalder

Good to know! Thanks for the testing.