Designing Great UIs for Progressive Web Apps
Progressive Web Apps give us an opportunity to reset our expectations and to loudly declare that We Can Do Better when designing user experiences on the web.
The keys to great Progressive Web App UX
- Always be testing on real world hardware
- Take UX inspiration from native apps
- Use the following checklist to ensure you’ve avoided common errors
Always be testing on real world hardware
When you start each new project, find the crappiest mobile device you can and set up remote debugging with Chrome. Test every change to ensure you start fast and stay fast.
Take UX inspiration from native apps
It’s totally possible to take a poor mobile website and slap on service worker caching to improve performance. This is worth doing, but falls well short of providing the full benefit of a Progressive Web App.
When it comes to visual design and interaction patterns, start by forgetting everything you know about conventional web design, and instead imagine you’re actually designing a native app. It’s important to pay attention to detail here since native apps have given users expectations around touch interactions and information hierarchy which are important to match to avoid creating a jarring experience.
Try related native apps on iOS and Android and browse sites like Dribbble for design inspiration. Spend some time browsing the Material Design Specification to level up your familiarity with common UI components and their interaction.
Use a checklist
There are a number of UX checklists for native apps that are worth Googling and verifying. I’ve personally noticed a number of common mistakes Progressive Web App developers make, which have been condensed down into the following recommendations:
Recommendation 1: Screen transitions shouldn’t feel slow due to blocking on the network
When a user taps a button or link in a web app, especially a server rendered web app, they are often made to wait staring at the current screen before suddenly jumping to a whole new screen of content.
This feels unresponsive and is unacceptable in a PWA (Progressive Web App) since betrays the idea that the app itself is running locally on the device.
Aim to provide the perception that the whole “app” is stored locally on the phone and that only the content is being dynamically loaded.
Example of this done well:
When a user taps on an article in Jalantikus, the PWA immediately navigates the user to the article page without blocking on the network. The user is shown the thumbnail and title which were already available locally, and then the article content and a higher resolution image fade in when they become available.
Tip: use a cache-first network strategy wherever possible as network-first strategies cause severe performance issues on slow or flaky networks.
Recommendation 2: Tappable areas should give touch feedback
When a button or tappable area is tapped, the user shouldn’t be left wondering if the tap was recognized.
Aim to make it immediately clear that the taps were recognized. For example this can be done by highlighting the tapped region in grey, showing a material ripple or having a page transition start immediately.
Tip: by default some browsers show their own highlight when elements are tapped. This default styling is unattractive and may conflict with your custom feedback (for example, Polymer Paper Buttons flash blue when tapped in Chrome for Android 😞), so either customize it or disable it by setting:
Example of touch feedback done well:
The Google I/O 2016 web app provides an immediate grey highlight when a talk is tapped and the default blue tap color is disabled.
Recommendation 3: Touching an element while scrolling shouldn’t trigger touch feedback
When implementing the touch feedback it is important that it doesn’t trigger mistakenly when the user is only touching an element to scroll the page.
Example of touch feedback given at the wrong time
An early version of the popular Material-UI library triggered ripples on touchable elements when they were touched during scrolls. The issue was fixed by aborting the ripple animation if the user’s touch location moved more than 6 pixels in any direction within the first few hundred milliseconds.
Recommendation 4: Content shouldn’t jump as the page loads
All img tags on a page should proactively include the dimensions of the image. This allows the browser to layout the screen correctly even before the image is loaded.
If dimensions aren’t specified on the tag then content will jump when the image is downloaded, which makes for a poor user experience.
Tip: show a placeholder where the image will go, such as a grey square, or a blurred thumbnail of the image if it is available on the client due to being shown on a previous screen. Fading in the image when it is downloaded is also a nice touch of polish.
Recommendation 5: Pressing back from a detail page should retain scroll position on the previous list page
When a user selects an item from a list and is viewing it’s details, tapping back should bring back to the list page with the same scroll position they were at before they pressed on the item.
It is very difficult to browse a list of articles, products or other items when pressing back always returns the user to the top of the list.
Tip: routers built into some frameworks may provide this functionality by default for you, but verify that they do.
Recommendation 6: Buttons and ‘non-content’ shouldn’t be selectable
In Chrome, single taps on text are sometimes interpreted as selections. This creates the bug that taps on buttons and other ‘non-content’ are sometimes identified as selections, resulting in a strange experience.
To resolve this issue, mark non-content elements with the following CSS property:
Example of non-content accidentally being selected
Here you can see an icon on a button has been accidentally selected by the user, resulting in a weird experience where the expected action doesn’t occur and the ‘contextual search’ feature in Chrome appears at the bottom of the screen.
Recommendation 7: Ensure inputs aren’t obscured by keyboard
Sometimes when a user taps on an input field the keyboard will be brought up in such a way that it obscures the input. Be sure to try scrolling to different positions on the page and then tapping the input element to be sure it is never obscured.
Tip: If the element is being obscured, explore using features like Element.scrollIntoView() to solve it.
Recommendation 8: Provide an easy way to share content
PWAs are often shown in a context where the current URL isn’t easily accessible, so it is important to ensure the user can easily share what they’re currently looking at. Implement a share button that allows users to copy the URL to the clipboard, or share it with popular social networks.
Tip: In many browsers you can automatically put content into users clipboards. Providing a share button that copies the URL of the current page to the clipboard is a nice model.
Recommendation 9: Use system fonts
Users will feel more at home in your Progressive Web App if you tweak it’s style to match their operating system. You can go so far as to implement different buttons and menus per platform, or simply get a head start by using the system’s preferred font:
/* iOS */
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
/* Android */
font-family: 'RobotoRegular', 'Droid Sans', sans-serif;
/* Windows Phone */
font-family: 'Segoe UI', Segoe, Tahoma, Geneva, sans-serif;
Recommendation 10: Avoid overly “web-like” design
“Classic” web design depends heavily on links in text, and static elements available on every page such as a header and a footer. These design elements are rarely found in native apps, so in order to match user’s mental models it is recommended to avoid these and use more app-like design instead.
Example: Links should be used sparingly. Use careful placement of buttons, or tappable regions of cards instead.
Example: Static page footers that contain navigation links and copyright information should be avoided. Take inspiration from native app design to see how similar information can moved into a menu or otherwise not included on every page.
Recommendation 11: Touch interactions should be implemented very well, or not at all
It is notoriously difficult, although not impossible, to implement advanced touch interactions such as pull to refresh and swipe to dismiss navigation menus.
If your app design requires advanced touch interactions, ensure the implementation is battle hardened and works well on real devices. Generally this means finding an implementation of this feature that somebody else has already crafted with great effort, such as the excellent react-swipable-views.
Tip: Much has been written about how ‘Hamburger Menus’ should be avoided for UX reasons. They have even been stripped out of a number of Google apps. Given the additional challenge of implementing their swipe interactions on the web, I would recommend against using them in Progressive Web Apps entirely.
We can build amazing user experiences in Progressive Web Apps
I’m excited that Progressive Web Apps allow us to build a new neighborhood on the web with no broken windows.
By testing on real devices, taking inspiration from native app designs and applying checklists we can build truly amazing experiences on the web.
Follow me on Twitter @owencm for more about Progressive Web Apps.
Thanks to the Chrome XFN team and the Lighthouse team for all your inspiration.