Skip to content
Go back

A Checklist of Issues for Progressive Web Apps and How to Fix them

Table of Contents

Open Table of Contents

Who This Post Is For

This post is a collection of pitfalls I ran into developing progressive web apps or PWAs (such as WeightBook) without testing on actual devices, especially iPhones. Looking at your app in the browser dev tools or an Android test device can only take you so far. If you are interested in hosting your PWA using nginx and kubernetes / docker, also have a look at Build a progressive web app in docker with nginx to deploy to kubernetes or docker swarm.

This is a living collection and might be sporadically updated when I encounter new issues ;).

Issues

1. Users Can Highlight All Text

By default, users can highlight text everywhere, for example, by long-pressing. This will show a context menu or auto-translate the highlighted text in an overlay.

To fix

Create a CSS class that prevents selecting text and apply it to any element that you do not want users to select text in. This class can be applied to UI elements where the user should not be able to highlight text, for example buttons or cards. If lazy, just apply it to body but be aware that it will disable text selection everywhere and be bad UX ;). See https://www.w3schools.com/howto/howto_css_disable_text_selection.asp.

.prevent-select {
    -webkit-user-select: none; /* Safari */
    -ms-user-select: none; /* IE 10 and IE 11 */
    user-select: none; /* Standard syntax */
}
Subscribe for more writing like this:

Powered by Buttondown ↗

2. Transparency in PWA Icons

Do not rely on a consistent background color for your PWA icons with transparent backgrounds. The initial icon for WeightBook was a black outline of a sheet of paper. It looked good in my testing and in light mode, but when users with dark mode installed it on their devices, the icon was just black.

To fix

Make sure the icons in your Web app manifest work on different backgrounds, especially in light and dark modes.

3. Background Scrolling on iOS

When scrolling to the edges, iOS adds an elastic bounce effect to even installed PWAs.

To fix

To remove this you can set a fixed body position on the body element:

body {
    position: fixed;
    left: 0;
    top: 0;
    right: 0;
    bottom: 0;
    touch-action: none;
}

(from Stack Overflow)

4. Notches Overlap Content

Camera lenses, top notches or (on iOS) overlays at the bottom can overlay the viewport of your PWA.

To fix

You can use safe-area-inset-* in your CSS to avoid those (see https://developer.mozilla.org/en-US/docs/Web/CSS/env#values). For example, add a safety padding around your content:

body {
    padding: env(safe-area-inset-top, 0px) env(safe-area-inset-right, 0px) env(safe-area-inset-bottom,
            0px) env(safe-area-inset-left, 0px);
}

Or create a CSS class to apply to elements that need additional padding:

.padding-bottom-inset {
    padding-bottom: calc(env(safe-area-inset-bottom, 0px) + 1rem);
}

To use these values, make sure to set the correct viewport meta tag, especially viewport-fit=cover:

<meta
    name="viewport"
    content="width=device-width, initial-scale=1.0, maximum-scale=1, viewport-fit=cover"
/>
Subscribe for more writing like this:

Powered by Buttondown ↗

5. Test Features That Require HTTPS Locally

Some features of your app (such as installing it ;)) might not work on emulators or your own devices if your app is served from HTTP origins, such as localhost.

To fix

For Vite, you can add @vitejs/plugin-basic-ssl to your project. A minimal plugin configuration to add to your defineConfig is:

export default defineConfig({
    plugins: [
        basicSsl({
            name: 'dev-text',
        }),
    ],
    // ... other configs
});

6. Android Appends .txt to Files With Unknown Mime Type

If you download a file with a mime type unknown to Android, it appends .txt. For example, a SQLite database export called weights.db becomes a text file named weights.db.txt.

To fix

Look up a fitting mime type on https://mimetype.io. If the mime-type you are offering does not work, check if it is correct (e.g., https://mimetype.io/application/vnd.sqlite3 shows “This mimetype is deprecated” for SQLite databases).

Assign a mime type to a file and offer it for download using (for example with application/x-sqlite3):

const fileToExport = // create the file ...
const file = new Blob([fileToExport], {
    type: `application/x-sqlite3`,
});

const fileUrl = URL.createObjectURL(file);

const a = document.createElement('a');
a.href = fileUrl;
a.download = 'weights.db';
a.click();
a.remove();

URL.revokeObjectURL(fileUrl);

7. Avoid Pull-To-Refresh

When dragging down, iOS triggers a pull-to-refresh.

To fix

Set overflow hidden on the body and show content in an element with overflow-y: scroll; and a fixed height:

body {
    overflow: hidden;
}

.page {
    height: 88dvh;
    overflow-y: scroll;
}

(from Stack Overflow)

In Summary

I can’t speak from recent experience, but I’ve previously used the Ionic Framework to reduce the mobile specific issues I’ve encountered and found it good to work with. So probably, do not do this yourself but work with a framework.


About Me

I research open data and collaborative data engineering. In another life, I build custom software and consult on data science and software engineering. Sometimes, I create (mostly digital) projects for fun.
For freelance work, project ideas or feedback, email me: philip@heltweg.org.
Subscribe for more writing like this:

Powered by Buttondown ↗


Share this post on:

Previous Post
The Open Data Value Chain
Next Post
Meta Data #1: Retroactive Public Goods Funding and Open Data in Web3 With David Gasquez