Indonesia Singapore ไทย Pilipinas Việt Nam Malaysia မြန်မာ ລາວ
← Back to Blog

Progressive Web Function: Why Parity Is the Wrong Goal

Stop building for the lowest common denominator — design for capability tiers and let platforms opt into richer experiences.

Editorial illustration of a figure navigating multiple diverging platforms, each with a different experience layer
Illustrated by Mikael Venne

Chasing identical functionality across every platform is costing your team velocity. Here's why progressive web function is the smarter architecture play.

Most web teams have quietly accepted that websites don’t need to look identical across browsers and devices. CSS progressive enhancement settled that argument years ago. But a subtler version of the same debate is back — and this time it’s about function, not form.

The Functional Parity Trap

Bram Van Damme’s recent piece puts it plainly: the expectation that websites must function identically on every platform is a constraint we’ve invented for ourselves, not one the web imposes. The comparison to visual design is instructive. When Chrome renders a clip-path and Firefox renders a flat box, nobody files a P1 ticket anymore. Yet when a swipe gesture works in one browser and degrades elsewhere, product managers reach for the escalation channel.

The cost of this instinct is real. Engineering teams burn sprint capacity papering over capability gaps with polyfills and fallback logic. QA matrices balloon. Release cycles slow. And the irony is that the users most affected — typically on mid-range Android devices, which account for the majority of Southeast Asian mobile traffic — would often be better served by a leaner, capability-matched experience than a feature-complete one running at half speed on a Redmi Note.

What View Transitions Actually Teach Us About API Strategy

The View Transitions API is a useful case study in capability-tiered thinking. Bramus’s breakdown of attr() versus match-element for setting view-transition-name values illustrates the kind of decision tree that good front-end architecture requires: both approaches work, but the right answer depends on your DOM structure, your browser support targets, and how much specificity your animation logic needs.

attr() — the approach Kevin Powell demoed at CSS Day — is elegant for pulling dynamic values directly from HTML attributes without touching JavaScript. match-element is more surgical, letting you target elements by reference rather than by attribute string. Neither is universally superior. The point is that the API itself is designed with optionality in mind: browsers that don’t support View Transitions skip the animation and navigate normally. No breakage. No fallback component. The feature layers in rather than gating the experience.

That’s the architectural posture worth generalising. If your feature requires a polyfill to function at all, ask whether it should be a feature or a progressive enhancement.


Capability Tiers as a Product Framework

The practical shift here isn’t technical — it’s organisational. Getting a product team to accept that Feature X will be unavailable on Safari 16 or Samsung Internet requires the same kind of stakeholder diplomacy as getting sign-off on a consent mode implementation that reduces attributed conversions by 15%. The numbers look worse on paper before they look better in practice.

The framing that tends to land: define capability tiers explicitly, upfront, in the product spec. Tier 1 is the baseline — the experience every supported device gets. Tier 2 is enhanced — available where the platform supports it, tested, but not required for launch sign-off. Tier 3 is progressive — shipped behind a feature-detect, monitored via RUM data, iterated on.

This mirrors how mature design systems scale across channels. Tokopedia and Grab both operate design and front-end systems where mobile web, native app, and desktop each have explicit capability contracts rather than a shared checklist. The result isn’t inconsistency — it’s appropriate fidelity per context.

The QA and Tracking Implications Nobody Talks About

Here’s the part that keeps me up at night: progressive function only works if your observability layer is built for it. If your analytics implementation fires the same event schema regardless of whether a user experienced the enhanced view or the baseline fallback, you’re flying blind on which tier is actually performing.

Tag your capability tier in the data layer. A simple custom dimension — experience_tier: 'enhanced' | 'baseline' — passed with every pageview and interaction event gives you the segmentation you need to assess whether the enhanced experience is actually moving the metrics you care about. Without it, you’re shipping capability-tiered UX and measuring it as if it were monolithic. That’s how you end up killing features that were working, or defending ones that weren’t.

Server-side tagging helps here too. When the measurement layer lives server-side, you have more control over event enrichment — you can append tier data, device capability signals, and consent state without depending on client-side JavaScript that may or may not have executed cleanly on a Tier 1 device.

The web platform is finally mature enough to support genuinely differentiated experiences by capability. The question is whether your team’s definition of ‘done’ is mature enough to match it.

Cryptic Grizzly

Written by

Cryptic Grizzly

Fluent in server-side tagging, consent-mode logic, and the intricate diplomacy of getting marketing and engineering to agree on a data layer. Nothing ships without a QA plan.

Enjoyed this?
Let's talk.

Start a conversation