Infrequently Noted

Alex Russell on browsers, standards, and the process of progress.

Effective Standards Work, Part 1: The Lay Of The Land

The web standards process fails us too often. This series explores the forces at work, how we're improving the situation, and how you can shape new features more effectively.

"Why don't browsers match standards!" muttered the thoughtful developer (just before filing an issue at "The point of standards is so that everything works the same."

Once something is in The Standard, everyone will implement interoperably...right?

Maybe. Confusion about how interoperability is really created sparks many of the worst arguments I've witnessed in my ~12 years working on web platform features.

Not every effort I've been involved in has succeeded (e.g. ES4), while some have but took too long. A few even went well. Having made most of the available mistakes, I was handed the responsibility to keep Chrome engineers from error as our "Web Standards Tech Lead". I don't write about it much because anything said is prone to misinterpretation; standards-making is inherently political. In the interest of progress, this 2-part series is a calculated risk.

Some problems on the web can be solved in userland. Others require platform changes. For historical and practical reasons, changes to the web platform must be codified in web standards. The community of web developers and browser vendors share this norm. Browsers are substitutable and largely rival goods.

Every party has reasons to value compatibility and interoperability. Developers benefit when interop extends the reach of their products and services. Browsers benefit from interop as end-users abandon browsers that can't access existing services and content. New features, then, require a trajectory towards standardisation. Features shipped without corresponding standards proposals are viewed critically. For business folks primed to hear "proprietary" as a positive, it can be surprising to encounter the web community's loathing of non-standard features.

From far enough away, it may appear as though new features "happen" at the W3C or WHATWG or ECMA or IETF. Some presume that features which are standardised at these organisations originated within them — that essential design work is the product of conversations in committee. If vendors implement what standards say, then surely being part of the standards process is how to affect change.

Standards Theory

This isn't how things work in practice, nor is it how feature design should work. Instead, new features and modifications are brought to Standards Development Organisations ("SDOs") by developers and vendors as coherent proposals. It's important to separate design from standards making. Design is the process of trying to address a problem with a new feature. Standardisation is the process of documenting consensus.

The process of feature design is a messy, exciting exploration embarked upon from a place of trust and hope. It requires folks who have problems (web developers) and the people who can solve them (browser engineers) to have wide-ranging conversations. Deep exploration of the potential solution space — discarding dozens of ideas along the way — is essential. A lot of the work is just getting to agreement on a problem statement. This is not what formal standards processes do.

For boring reasons of IP licensing, anti-trust law, and SDO governance, chartered Working Groups (e.g., at the W3C) state what it is they're going to deliver, often years before they actually do. Some SDOs require "signs of life" from potential implementers (usually 2 or more) to progress in their processes. IETF famously refers to this as "running code and rough consensus". Clear problem statements and potential solutions must be proposed and partially agreed to even get a hearing. This puts formal standards-making late in the process (when done correctly).

TL;DR: SDOs and their formal Working Groups aren't in the business of feature design.

SDOs and Working Groups can't tell you if a design solves an important problem or solves it well. They are set up to pass judgement on the details of a specification and a consensus surrounding the specific words in spec documents.

Working Groups and SDOs are not fitness functions for features.

Getting a design through committee says next to nothing about its quality. Many an august and thoughtful person has engaged in outrageous groupthink when these processes are asked to predict the future rather than document consensus. Without developers trying a feature and providing feedback, Working Groups quickly wander into irrelevant pastures. And who's to tell them they're wrong? They are staffed with experts, after all!

SDOs are best understood as amplifiers: they take raw inputs, filter them to prevent major harm if played at top volume, then use processes to broadcast them. How the inputs came to be gets obscured in this process.

I can report these histories aren't lost, but they are unattractive. Participants have reasons not to tell them — boredom with a topic, the phantom pain of arguments nearly won, and the responsibilities of statesmanship towards counterparties. Plucky documentarians sometimes try, but standards dramas don't exactly jump off the page.

When the deeper histories aren't told or taught, it becomes hard for newcomers to get oriented. There's no effective counter-narrative to "progress come from standards bodies", and no SDO is going to turn down new members. Nobody tells developers not to look to SDOs for answers. Confusion reigns.

The Forces At Play

Feature design starts by exploring problems without knowing the answers, whereas participation in Working Groups entails sifting a set of proposed solutions and integrating the best proposals. Late iteration can happen there, but every change made without developer feedback is dangerous — and Working Groups aren't set up to collect or prioritise it.

Even when consensus is roughly achieved, standards processes are powerless to compel anyone to implement anything, even Working Group participants! Voluntary standards are not regulations. Implementers adopt standards because customers demand interoperability to hedge against vendor market power.

It can't be repeated enough: the fact of something appearing in a web standard compels nobody to implement, even those who implemented previous versions. This flows from the fundamental relationships between browsers, developers, and users.

Browser vendors exercise absolute control over the bits in their binaries because they need to do what's best for users. A standard might declare that creates a new browsing context, yet browsers block popups in practice. Chrome has even formalized this idea of "interventions".

Preventing abuse is one thing, but perhaps new features are different? A browser can add dozens of proprietary features, but if developers decline to adopt, users don't benefit. Developer adoption is frequently gated on interoperability, a proxy for "can I reach all the users I want to if my app requires this feature?" That is, developers often decline to use features that aren't already in every engine they care about.

Circularly, non-implementing engines view features without broad use as cost rather than potential benefit. This is particularly true when the alternative is to improve performance of existing features. A sure way for a browser engineer to attract kudos is to make existing content work better, thereby directly improving things for users who choose your browser. Said differently, product managers intuitively prefer surefire improvements to their products rather than speculative additions which might benefit competitors as much (or more). Enlightened ecosystem thinkers are rare, although the web has been blessed with several of them recently.

Last, but not least, a lack of solidarity looms over the enterprise. Browser engineers don't make websites for a living, so they also lack intrinsic motivation to improve the situation. Many an epic web standards battle to advance an "obviously" missing feature can be traced to this root.

Note: the whole ecosystem breaks down when users do not have a real choice of engine, e.g. on iOS. When competition is limited vendors are free to structurally under-invest and the platform becomes less dynamic and responsive to needs. Everyone loses, but it's a classic deadweight loss, making it harder to spot and call out.

The status quo is powerful. Every vendor has plausible (if played-up) reasons not to implement new features. They can stall progress until they are last (or second-to last in a 4+ party ecosystem) to implement. There's no developer wrath until that point, and it's easy to cast FUD on not-yet-pervasive features while holding a pocket veto. Further, it's the job of SDOs and formal Working Groups to kill ideas that are not obviously fit for purpose or which lack momentum.

This situation looks hopeless for folks trying to make progress. The slow pace of some essential but overdue improvements (Responsive Images, CSS variables, ES6 Classes, Promises & async/await, Web Components, Streams, etc.) would give any sane observer pause. Is it worth even trying?

The enormous positive impact that changes to the web platform can deliver makes me believe the answer is "yes". In Part 2 I'll share details of how the Chrome Team changed its thinking about feature development and standards and how that's enabling the entire web community to deliver more progress faster.

Keep Reading: Part 2, Threading The Needle

Hearty thanks to Andrew Betts, Bruce Lawson, and Mariko Kosaka for reviewing drafts and correcting many of my innumerable errors.

Can You Afford It?: Real-world Web Performance Budgets

TL;DR: performance budgets are an essential but under-appreciated part of product success and team health. Most partners we work with are not aware of the real-world operating environment and make inappropriate technology choices as a result. We set a budget in time of <= 5 seconds first-load Time-to-Interactive and <= 2s for subsequent loads. We constrain ourselves to a real-world baseline device + network configuration to measure progress. The default global baseline is a ~$200 Android device on a 400Kbps link with a 400ms round-trip-time ("RTT"). This translates into a budget of ~130-170KB of critical-path resources, depending on composition -- the more JS you include, the smaller the bundle must be.

We've had the pleasure of working with dozens of teams over the past few years. This work has been illuminating, sometimes in very unexpected ways. One of the most surprising results has been the frequent occurrence of "ambush by JavaScript":

We need a new term for the business-opportunity wastage that modern front-end development has created.

Maybe "ambush by JS"?

Business leaders who green-light the development of Progressive Web Apps frequently cite the ability to reach new users with near-zero friction as a primary motivator. At the same time, teams are reaching for tools which make achieving this goal impossible. Nobody is trying to do a poor job, and yet the results of a "completed" PWA project often require weeks or months of painstaking rework to deliver minimally acceptable performance.

This rework delays launch which, in turn, delays gathering data about the viability of a PWA strategy. Teams we aren't able to work with directly sometimes do not catch these problems until it's too late, launching experiences which are simply unusable for all but the wealthiest.

Setting A Baseline

Teams that avoid unpleasant surprises tend to share a few traits:

These properties build on each other: it's difficult to get the space you need to plan to do things well without decision makers who value user experience and long-term business value. Teams with this support are free to set performance budgets, do "bakeoffs" between competing approaches, and invest in performance infrastructure. They're also more able to go against the "industry standard" grain when popular tools prove to be inappropriate.

Performance budgets keep everyone on the same page. They help to create a culture of shared enthusiasm for improving the lived user experience. Teams with budgets also find it easier to track and graph progress. This helps support executive sponsors who then have meaningful metrics to point to in justifying the investments being made.

Budgets set an objective frame for determining which changes to the codebase represent progress and which are regressions from the user perspective. Without them it's impossible to avoid slipping into the trap of pretending you can afford more than you can. Very rarely have we seen a team succeed that doesn't set budgets, gather RUM metrics, and carry representative customer devices.

Partner meetings are illuminating. We get a strong sense for how bad site performance is going to be based on the percentage of engineering leads, PMs, and decision makers carrying high-end phones which they primarily use in urban areas.

Doing better by users involves 2 phases:

Never before have front-end teams enjoyed access to such good performance tools and diagnostic techniques, yet poor results are the norm. What's going on here?

JS Is Your Most Expensive Asset

One distinct trend is a belief that a JavaScript framework and Single-Page Architecture (SPA) is a must for PWA development. This isn't true (more on that in a follow-up post), and sites which are built this way implicitly require more script in each document (e.g., for router components). We regularly see sites loading more than 500KB of script (compressed). This matters because all script loading delays the metric we value most: Time to Interactive. Sites with this much script are simply inaccessible to a broad swath of the world's users; statistically, users do not (and will not) wait for these experiences to load. Those that do experience horrendous jank.

We're often asked "what's the big deal about 200KB of JS, some of our images are that size?" A good question! Answering it requires an understanding of how browsers process resources (which differs by type) and the concept of the critical path. For a timely introduction, I recommended Kevin Schaaf's recent talk.

Late-loading JavaScript can cause "server-side rendered" pages to fail in infuriating ways. This uncanny-valley effect is the reason we focus on when pages become reliably interactive.
Consider a page like:
<!DOCTYPE html>
<link rel="stylesheet" href="/styles.css">
&lt;script src="/app.js" async&gt;&lt;/script>
<picture slot="hero-image">
srcset="img@desktop.png, img@desktop-2x.png 2x"
media="(min-width: 990px)">

srcset="img@tablet.png, img@tablet-2x.png 2x"
media="(min-width: 750px)">

srcset="img@mobile.png, img@mobile-2x.png 2x"
alt="It's a perfectly cromunlent word!">


The browser encounters this document in response for a GET request to The server sends it as a stream of bytes and when the browser encounters each of the sub-resources referenced in the document, it requests them.

For this page to be done loading it needs to be responsive to user input -- the "interactive" in "Time to Interactive". Browsers process user input by generating DOM events that application code listens to. This input processing happens on document's main thread, where JavaScript runs.

Here are some operations that can happen on other threads, allowing the browser to stay responsive:

These operations, however, must happen on the main thread:

If our example document wasn't reliant on JavaScript to construct the <my-app> custom element, the contents of the document would likely be interactive as soon as enough CSS and content was available to render meaningfully.

Script execution delays interactivity in a few ways:

Images, on the other hand, do not block the main thread, do not block interaction when parsed or rasterized, and do not prevent other parts of the UI from getting or staying interactive. Therefore, while a 150KB image won't appreciably increase TTI, 150KB of JS will delay interactivity by the time required to:

These steps are largely serialized.

If script execution could stay under 50ms for a bundle this large, TTI would not be delayed, but that's not feasible. 150KB of gzipped JavaScript expands to roughly 1MB of code, and as Addy documented, that's going to take more than a second on most of the world's phones not including the time to fetch it.

JavaScript is the single most expensive part of any page in ways that are a function of both network capacity and device speed. For developers and decision makers with fast phones on fast networks this is a double-whammy of hidden costs.

Global Ground-Truth

Deciding what benchmark to use for a performance budget is crucial. Some teams and businesses know their audience intimately and can make informed estimates about the devices and networks current and prospective users are on. Most, however, do not have such a baseline easily to-hand. Where to start?

Two numbers set the stage:

The median user is on a slow network. Just how slow is a matter of some debate.

Our metrics at Google show a conflicted picture (which I'm working to get to clarity on). Some systems show median RTTs near ~100ms for 3G users. Others show the median user unable to transmit and receive an individual packet in less than 400ms in some major markets.

I suggest we should be conservative. Contended, over-subscribed cells can make "fast" networks brutally slow, transport variance can make TCP much less efficient, and the bursty nature of web traffic works against us.

Googlers enjoy access to a simulated "degraded 3G" network to help validate the behaviour of their apps under these conditions. It simulates a link with a 400ms RTT and 400-600Kbps of throughput (plus latency variability and simulated packet loss). Given the conflicted data we see across our other systems, this seems about right as a baseline.

Simulated packet loss and variable latency, however, can make benchmarking extremely difficult and slow. The effect of a lost packet during DNS lookup can be a difference of seconds, making it frustrating to compare before/after for changes at development time. Our baseline, then, should probably trade lower throughput/higher-latency for packet loss. What we lose in real-world fidelity, we gain in repeatability and the ability to compare across changes and across products. There's much, much more to say about the effects of DNS, TLS, network topology, and other factors. For those who want to go deeper on this, I highly recommend Ilya Grigorik's "High Performance Browser Networking". The coverage of RRC alone makes it worth your time.

Back to our baseline, we now have a sense for what our simulated network conditions should be: 400ms RTT, 400Kbps bandwidth. What about the device itself?

At last year's Chrome Dev Summit I discussed some of the thermal and power-limiting factors that create a huge disparity between desktop and mobile device performance. Add onto that the yawning chasm between low-end and high-end device performance thanks to chip design factors like cache sizes, and it can be difficult to know where to set a device baseline. Thankfully, this is somewhat easier than network speeds: more than half of American mobile users are on Android devices. As you look abroad, worldwide smartphone shipments are (and for the past 5 years have been) overwhelmingly Android-based. The average selling price for those devices is falling in most geographies, driven by the ubiquity of Android and relentless price drops within that ecosystem. This, in turn, drives the single most important trend in setting the global web performance budget hardware baseline: the next billion users will largely come online when they can afford to. This will drive declines in smartphone average-selling-price ("ASP") in emerging markets for the foreseeable future. This, in turn, means that all improvements to transistor-count-per-dollar will translate into lower selling prices, not faster devices (on average).

The true median device from 2016 sold at about ~$200 unlocked. This year's median device is even cheaper, but their performance is roughly equivalent. Expect continued performance stasis at the median for the next few years. This is part of the reason I suggested the Moto G4 last year and recommend it or the Moto G5 Plus this year.

Putting it all together, our global baseline for performance benchmarking is a:

For most technologists, building applications for this environment might as well be farming on Mars. Luckily, this configuration is available on, meaning we can re-create these conditions here on earth, any time we like.

The Affordability Calculation

The last thing we need for our perf budget is time. How long is too long?

I like Monica's definition:

The Monica Perf Test™: if you wouldn't make eye contact with a stranger for the time it takes your web app to first paint, it's too slow.✌️💫

...but that's more qualitative than quantitative. Numerically, we'd prefer every page load occur in under a second (see RAIL). That's not possible on real-world networks, so we've set the following Time-to-Interactive (TTI) metric goal with partners:

We now have everything we need to create a ballpark perf budget for a product in 2017.

First Load

Working backwards from time, network conditions, and the primary stages of the critical path, we get a few interesting results. We can start with our first-load budget of 5 seconds and begin to calculate how much transfer we can afford.

First we subtract 1.6 seconds from our budgets for DNS lookup and TLS handshaking, leaving us 3.4s to work with.

Then, we calculate how much data we can send over this link in 3.4 seconds: 400 Kbps = 50KB/s. 50KB/s * 3.4 = 170KB.

NOTE: This discussion is sure to infuriate competent network engineers. Previous versions of this article discussed slow-start, bdp, tcp window scaling, and the like. They were commensurately difficult to follow. Simplifying has relatively little impact on the overall story, so those details are elided.

Modern web applications are largely composed of JS, meaning we also need to subtract the amount of time the JS needs to parse and evaluate. The gzip compression factor for JS code is between 5x and 7x. 170KB of JS then becomes ~850KB-1MB of JS which, based on earlier estimates, may take a second to run (presuming it doesn't do any expensive DOM work, which of course it will). Playing with these numbers a little bit, we can get back below 3.4s of download and eval by limiting ourselves to 130KB of JS transferred on the wire.

One last wrench in the works: if any of our critical-path resources come from a different origin (e.g., a CDN), we need to subtract connection setup time for that origin (~1.6s) from the budget, further limiting how much of our 5s we actually get to can spend on network transfer and client-side work.

Putting it all together, under ideal conditions, our rough budget for critical-path resources (CSS, JS, HTML, and data) at:

This gives us the ability to consider the single most pressing question in front-end development today: "can you afford it?"

For example, if your JS framework takes ~40KB of transfer on a JS-heavy site (which gets a budget of 130KB thanks to JS eval time), you're left with only 90KB of "headroom". Your entire app must fit into that space. A 100KB framework loaded from a CDN is already 20KB over budget.

Think back: your framework of choice might be 40K, but what about that data system? The router you added? Suddenly 130KB doesn't seem like a lot when you also need to include data, templates, and styles.

Living on a budget means constantly asking yourself "can I really afford this?"

Second Load

In an ideal world, all page loads happen in under a second, but for many reasons that's often not feasible. Therefore we're going to give ourselves a bit of a breather and budget 2 seconds for second (third, fourth, etc.) load.

Why not 5? Because we shouldn't need to ever go to the network to get our app's UI booted once we've visited it the first time. Service Workers and "offline first" architectures enables us to put interactive pixels on screen without ever touching the network. This is the key to achieving reliable performance.

Two seconds is forever in modern CPU terms, but we still need to spend it wisely. Factors we need to account for include:

Every app I've seen that hits a 5s initial load and implements offline-first correctly stays under this 2s budget, and sub 1s is possible! But getting to offline-first is a huge challenge for many teams. Architecting to save last-seen user data locally, cache app resources in a reliable and coherent way, and juggle application code upgrades using the Service Worker lifecycle can be a major undertaking.

I'm looking forward to tools continuing to evolve in this area. The most comprehensive bootstrap I know of today is the Polymer App Toolbox, so if you're not sure where to start, start there.

130-170KB...Surely You're Kidding!?!

Many teams we talk to wonder if it's even possible to deliver something useful in as little as 130KB. It is! the PRPL pattern shows the way through aggressive code-splitting based on route awareness, Service Worker caching of granular (subsequent-page) resources, and clever use of modern protocol enhancements like HTTP/2 Push.

Taken together, these tools enable us to deliver functional, modern experiences in under 100KB for the critical path.

Sadly, it's still sort of difficult to tell from a specific trace which parts of the page load are critical-path resources for TTI and which aren't, but I'm optimistic that tools will evolve quickly to help us understand this key metric.

Regardless, we know it's possible, even without giving up on frameworks entirely. Both Wego and are built with modern tools (Polymer and Vue, respectively) and help users complete real transactions today. Most apps are less complex than they are. Life on a budget isn't starvation.

Tools for Teams on a Budget

Getting under-budget is hard, but the benefits to the business and to users are immense. Less often discussed are the benefits to engineering teams and their leaders. No tech-lead or PM wants to be on the wrong side of an executive who walks into their area with a phone asking "so why is this so slow when I'm on vacation?"

This isn't theoretical.

I've seen teams that have just finished re-building on a modern tech stack cringe for an hour as we walk them through the experience of using their "better", "faster" experiences under real-world conditions.

Everyone loses face when the product fails to meet expectations. Months of unplanned performance fire-fighting delay the addition of new features and have a draining effect on team morale. When performance becomes a crisis, mid-level managers get caught between being the "shit umbrella" their teams count on and crushing self doubt. Worse, they may begin to doubt their team. The other side of a performance crisis is a long road; how can the organisation trust the team to deliver a quality product? Can they trust the TLs to recommend new technology or large re-investments? Recriminations follow. This is a terrible experience, specifically for developers who are too often on the receiving end of incredible pressure to "fix it", ASAP -- and "it" may be a core technology the product is built on.

In the worst cases, the product may be unfixable on a short enough timeframe to help the business. A lot of progress is Darwinian and for startups and small teams, betting on the wrong stack without the benefit of a long runway can be fatal. Worse, this can go un-diagnosed for a long, long time. If the whole team carries the latest iOS devices on fast, urban networks and the product's economics are premised on growing a broad-based audience, the failure of that audience to arrive barely makes a sound.

Performance isn't the (entire) product, of course. Lots of slow or market-limited products do incredibly well. Having a unique service that people want (and will go out of their way for) can override all of these other concerns. Some folks even succeed in App Stores where friction-to-acquire an experience is intense. But products in competitive marketplaces need every advantage.

Some specific tools and techniques can help teams that adopt a performance budget:

Success in combating bloat often means turning warnings into hard errors. Teams with CI or commit-queue systems should strongly consider disallowing commits that break the (performance) bank.

For teams starting fresh, my strong recommendation is to start with a stack that embeds strong opinions about app structure, code splitting, and build targets. The best of those today are:

Whatever tools your team chooses, a budget is essential. Without one, even the most advanced, "lightweight" frameworks can easily create bloated, unusable apps. Starting from the global baseline and only increasing the budget based on hard numbers is the best way I know of to ensure your project lands well for everyone.


In the interest of time and space, discussion of future-friendly architectures will have to wait for another post. The curious can dig into Service Workers, Navigation Preload, and Streams. Their powers combined are going to fundamentally transform the optimal page-load for 2018 and beyond.

Lastly, thanks to everyone who reviewed early drafts of this post, including (but not limited to): Vinamrata Singal, Paul Kinlan, Peter O'Shaughnessy, Addy Osmani, and Gray Norton. Hopefully their valiant attempts to direct this article away from error were not overcome by my talent in adding it.

Web Components: The Long Game

Mikeal Rogers reached out last week to talk about Web Components, which surprised me, but his follow-up blog post is essential, timely reading.

Dimitri Glazkov, Alex Komoroske, and I started the project that designed and (for many years) iterated on Web Components with a few primary goals in mind:

All of this was wrapped up in our project's mantra: "say what you mean".

Our position was (and is) that developers shouldn't need to write the word function when they meant class or module and they shouldn't have to type <div class="tree-control"> or torture existing HTML elements to "mean" something they clearly did not. JavaScript programmers should be able to instantiate components naturally (new TreeControl(...)) and that shouldn't need to be an exclusive choice that implicitly forces web developers to pick JS over HTML or vice versa. A componentized future should not exclude those who compose UIs in HTML. That means components need to participate in the built-in deserialization system: the HTML parser.

Web developers shouldn't need build steps or an expensive runtime systems to re-create parsing. Nor should typing <tree-control> in your markup require a specific framework to "fake" parser integration with custom, per-framework timing and lifecycle management (a source of much incompatibility).

When Different Isn't Better

When we started the "Parkour" project in 2010, members of the team had built something like a dozen JavaScript frameworks or component systems between them and those systems were powering the front-ends of billion-dollar businesses and used by thousands of engineers every day.

None of them could meaningfully share components or code.

Each of these tools became inadvertently totalizing when used at scale. The cost of the framework code was a major concern, and pulling in components from different frameworks implied pulling in all of the support code required to bootstrap the component models of each system. Maybe that would be palatable for a particularly juicy component (data grid, anyone?), but interop was more frequently stymied by the need to wrap components. The decision of which abstraction to interoperate on implicitly creates a situation where teams must pick "their" framework and then make components from other systems work within those terms.

It doesn't take a lot of familiarity with the history of JS frameworks to note a wide diversity amongst successful tools on a number of important axes: the most productive and efficient way to instantiate components, how and when configuration takes place, how data and configuration are updated, the lifecycle of the component, ownership of (and access to) managed DOM nodes, markup integration, and much more. Templating systems are relatively pluggable, but the thing about frameworks is that they set the terms of everything that happens in components. When frameworks make different choices (and they do), compatibility is the first casualty.

At this drilled-in level, we will no doubt endlessly debate these choices. Businesses trying to make durable investments, however, are forgiven for growing weary of the predictable outcomes: teams decide on the "best" tool, invest heavily in building (or using) components, only to discover that the next app or the next team makes a different choice. This creates a compatibility quandary as soon as anyone wants to re-use anything. Just upgrading from Version N of a framework to Version N+1 frequently creates this sort of problem. The painstaking work of building accessibility, shared styles, and reasonable performance into components often looks like good money after bad.

At a fundamental level, this happens because when JavaScript is the component model, all the choices are up for grabs. It might seem like there's some "lower level" interop to be gained by modeling everything in pure JS (not DOM), but this is a mirage. I'm not sure what the correct model is for this recipe for incompatibility, but the complexity of achieving compat seems intuitively to be O(N^2) or worse. Every major decision represented within a framework makes reaching compatibility with another framework exponentially harder. This is multiplied by the set of hopefully-interoperable frameworks.

Finally, the incentives of framework authors are not aligned with compatibility. Competition between JavaScript frameworks is fierce, and every tool that thinks it will "win" has a natural inclination to grow the set of components that are exclusive to the framework. A large, high quality control set is a compelling selling point, after all.

There are also costs associated with compatibility. First, compatibility requires stability and a commitment to a specific design. This ham-strings framework authors who (rightly) value the ability to change their minds and adapt to better ways of approaching problems. Second, the overhead of compatibility testing for the matrix of frameworks detracts from other priorities (performance, accessibility, "developer experience") that frameworks are judged on; particularly at adoption time. Where would this time-consuming work take place? Conference calls? How often? Who's organising and paying for it?

No matter how much businesses want the ability to reuse components, JavaScript frameworks as we know them are never going to deliver interop. It's called "framework churn" and not "component mixing" because to adopt the new thing the old one must be plowed under.

Wither Interop?

It's sobering to think that the endless framework churn has been with the JavaScript community for as long as we've been writing sizable apps. For me, that's more than 15 years. The evidence has been heard and verdict is in: there is no such thing as component longevity with interoperability so long as our abstraction is JS.

The deep reason for this is that all modern JavaScript UI frameworks manage two trees:

  1. The logical tree of high-level components ("widgets") which developers use to construct their applications
  2. An internal tree of managed DOM for each widget

Frameworks are in the business of providing the abstraction for the logical tree, a system for creating and managing widget internals, and (most importantly), systems for preventing widget internals from leaking into the logical tree. Until now, the only game in town for creating this encapsulation has been to create a tree that's parallel to the one exposed in the DOM.

Before the arrival of Shadow DOM, there was no way to avoid airing all of a component's dirty laundry (managed DOM) in the overall tree structure of the document. Component authors need to operate on the bits of DOM that they "own" and manage, whereas component users usually want to avoid seeing, touching, or interfering with the implementation details of the components they're composing into an app.

Custom Elements and Shadow DOM eliminate the need for a separate tree and traversal system. Together, they allow the developer to surface their component as a first-class citizen within the existing contract (HTML and the resulting DOM) whilst hiding the implementation details from casual traversal and interference. This is a trick that the built-in elements (think <video> or <select>) have been able to do forever, but until now it has not been available to us muggles.

Web Components represent something fundamentally different from the status quo. No other approach is able to actually eliminate the need for parallel trees.

The kicker is that Web Components are a web standard. The half-decade argument about what the lifecycle methods should be called, what they should do, and how it should all fit together has concluded. What's shipping in Chrome and Safari and Opera and Samsung Internet and UC Browser today is not something that can change easily (for better and for worse). This is a contract that a major fraction of the web relies on; it cannot be removed. The browsers that haven't shipped yet are under huge pressure to do so.

If you're a tech-lead or manager for a web team, it's time to consider how and when you'll transition to Web Components and what value frameworks add when most of their function has been supplanted by the platform. Forward-looking teams like Ionic are making this transition, and the results are incredible.

Many abstractions and tools that were developed in the context of a specific framework may come unglued, and a large-scale re-orientation of the framework landscape is likely. What remains will be systems that provide value further up the stack and tout interoperability as a feature.

Beyond Interop

In the talk I gave a few weeks back at the Polymer Summit, I went into detail about the performance motivations for some of the original Parkour work:

One of the best outcomes from delegating our component model to the platform is that, when we do, many things get cheaper. Not only can we throw out the code to create and manage separate trees, browsers will increasingly compete on performance for apps structured this way. Work over the past year in Chromium has already yielded significant speedups for Custom Elements and Shadow DOM, with more on the way. Platform-level scoping for CSS via Shadow DOM has enabled sizable memory and compute wins for style resolution, and overall re-architecture of the system benefits custom elements in ways that user-space won't benefit from as significantly.

Ignoring all of that, Mikeal's core point resonates strongly:

Our default workflow has been complicated by the needs of large web applications. These applications are important but they aren’t representative of everything we do on the web, and as we complicate these workflows we also complicate educating and on-boarding new web developers.

One of the things we'd hoped to enable via Web Components was a return to ctrl-r web development. At some scale we all need tools to help cope with code size, application structure, and more. But the tender, loving maintenance of babel and webpack and NPM configurations that represents a huge part of "front end development" today seems...punitive. None of this should be necessary when developing or using one (or a few) components. Composing things shouldn't be this hard. The sophistication of the tools should be proportional to complexity of problem at hand. Without a common component model, that will never be possible.

I'm excited we're finally there.

What, Exactly, Makes Something A Progressive Web App?

Since Frances and I published a blog post last year introducing Progressive Web Apps, a healthy conversation has started about what is and isn't a PWA. There are a lot of opinions and many shades of gray. What are the hard requirements? Which requirements are marginal? What's aspirational? This article outlines these requirements, attempts to classify them, and provides a baseline for "what is a Progressive Web App?"

Browsers gate Progressive Web App installation prompting and badging on criteria that they detect when users navigate to sites. These criteria have been designed to ensure that sites which invoke prompts are reliable, fast, and engaging.

Chrome's Progressive Web App Install prompt on the Polymer Shop demo.
Chrome's Progressive Web App Install prompt on the Polymer Shop demo.

I'd know. In January 2015 I designed the criteria that Chrome uses to trigger "Add to Homescreen" prompts. These prompts are what let users know that a site is a Progressive Web App. Sites that earn a spot on the homescreen report increased long-term engagement with these users.

Questions remain about what criteria browsers should enforce to gate prompting; that conversation is healthy, but this article isn't a contribution to it. Similarly, per-browser criteria are not cataloged. Instead, this article focuses on the strictest common criteria to ensure broad installability as of late 2016. Proprietary and legacy technologies (e.g., AppCache) are also out of scope as they don't contribute to prompting. This article is a time-capsule. The set of things you need to do today to cause your site to be recognized by browsers and bots as an installable Progressive Web App.

In general, installability criteria are tightening. Today's Good-To-Haves may become part of tomorrow's baseline. The opposite is unlikely because at least one major browser has made a strong commitment to tightening up the rules for installability.

Baseline Appyness

A Progressive Web App is functionally defined by the technical properties that allow the browser to detect that the site meets certain criteria and is worthy of being added to the homescreen. These criteria are motivated by user-experience concerns. Apps on the homescreen:

These concerns give rise to today's Baseline Criteria. To be a Progressive Web App, a site must:

Browsers do not enforce these requirements uniformly but if a browser does prompt for installation, sites that do these things will be installable today.

Plugged-in readers may note that no browser enforces the requirements about loading quickly on flaky connections or loading while offline. Enforcement is coming shortly; at least to Chrome.


Some criteria are situational or specific to particular form-factors. For example, an immersive game may need to run full-screen and may only want to work in a single orientation. That set of choices is an anti-pattern for a news app. Similarly, not every app needs to send users Push Notifications. This means that the following should be thought of as a score over-and-above the lowest passing grade. In US educational terms, doing well in these criteria will be the difference between a C- and an A-:

A+ Progressive Web Apps

A+ apps need to meet the highest experience bar. To hit this bar, A+ Progressive Web Apps (in addition to the above) should:

Great UIs take effort to build and polish, but the results can be incredible both for users and businesses. Frameworks are starting to adapt to these demands, e.g. the PRPL pattern and similar architectures for high-performance app loading, making it easier than ever to deliver amazing experiences on the web that hit all of the PWA high notes.

Getting Ready For Prime Time

That's a lot to think about!

Verifying that your PWA meets some of most of these criteria, specifically the baseline requirements, has required a great deal of manual testing…until recently. Thanks to the new Lighthouse project, it's possible to automate checks for many of these properties. You can even integrate Lighthouse into continuous integration systems to catch regressions.

DevTools is also improving rapidly to help you see the impact of changes. The new Security and Applications tabs allow quick diagnosis of common gotchas at development time.

Building a high-quality Progressive Web App has incredible benefits. A great experience can delight users and improve business outcomes. A bit of up-front planning, on-device testing, and iteration with Lighthouse can make it easier to realise them.

Endnote: Representative Devices

Performance testing is difficult!

A primary issue is the broad diversity in network and device performance. Developers tend to own devices (both desktop and mobile) that are significantly faster than the devices their apps will be experienced on. Many developers I've spoken with have never used chrome://inspect. They are frequently surprised to find their applications to be unacceptably slow on real phones.

To avoid this, it's imperative to be testing on real phones. But which ones? In an ideal world, automated testing of real-world performance would be trivially available in our continuous integration systems. Lighthouse attempts to emulate some aspects of mobile devices to provide actionable insight, but teams who are striving for A+ status need mid-tier devices to verify these results on.

Which ones to buy? The answer is market-dependent. The broader a service's reach, the lower-end the target phone should be. Networks also differ by market. "3G" often means something wildly different in practice in different geographies and even when users may have access to LTE service in theory, changing network conditions frequently put users into slower connections.

In late 2016, the following phones & testing settings strike a decent balance for their markets:

These recommendations attempt to be middle-of-the road in terms of price and capability. If your team is going for the best possible experience, don't be afraid to standardise on cheaper or older devices!

PWA Discovery: You Ain't Seen Nothin Yet

Ada pitched into the conversation about the state of PWAs -- particularly Chrome's heuristics which prompted a Twitter discussion about some of the finer points of the user and developer experience. The background to these conversations is that today, the way users learn that they can install a Progressive Web App is via a prompt browsers decide to show at their discretion. The reason for heuristics is the quality bar that Ada so deftly summarized (and which Remy had an "aha!" moment about recently):

In the case of Chrome it encourages web app developers to build using newer Web Technology such as Service Workers and Web App manifest. It is great because it encourages the building of Web Apps as opposed to native by greatly reducing the barrier to getting your company’s app on the user’s home screen.

Andrew called this a "bag of carrots" and he's not entirely wrong. When I designed the heuristics that Chrome uses to designate something worthy of prompting it was with the user values of reliable performance, ease of recall, and long-term security in mind. Any site can continue to live all its days in a tab; nothing is taken away from that mode. PWAs are about adding new capabilities to existing ones.

The browser's goal is clear: create a hurdle tall enough that only sites that meet user expectations of "appyness" will be prompted for. Maybe Chrome's version of this isn't great! Feedback like Ada's, Andrew's, and Jeremy's is helpful in letting us know how to improve. Thankfully, in most of the cases flagged so far, we've anticipated the concerns but maybe haven't communicated our thinking as well as we should have. This is entirely my fault. This post is my pennance.

Prompting: The First, Worst Guess

The prompting solution to PWA discovery was our first, worst guess at how to communicate to users that they are on a site that can act like an app. Despite the prompt's defects, it bootstrapped what we now think of as "Progressive Web Apps" with Chrome, Samsung Internet, and Opera all implementing versions of it in their Android browsers (note: no browser on iOS supports this as Apple [prevents meaningful competition][13]).

Getting just this much done was an enormous lift. The team had to overcome organisational skepticism that, bluntly, was daunting. Like "when this is all over I'll write a book and it will not be a comedy" daunting. If you think Google is a one big happy family or has "A Plan (TM)" encourage you to apply! They can't fire me for encouraging smart folks to work here, right? Regardless, we pulled it off. But an early first attempt, no matter how difficult, isn't going to be where PWA discovery ends.

Obviously I can't talk about what Chrome will or won't ship -- I have neither the power nor the crystal ball required to make statements like that -- but I can outline a few alternatives to the current "go to, use it for a while, do a jig, pray for the prompt" approach to PWA discovery. I'll also take a moment to cover some of the FAQs about the current design, including Ada's.

Engaged-user Prompting

"Engaged-user prompting" is the current (and in Chrome today, only) way to discover that a site you're on is a Progressive Web App. Remy recently noted why it wasn't a crisis that this doesn't mirror app-store listing: the main action that users need to perform to discover the content is the same thing they do to use the site/service. Progressive Web Apps cut out the App Store middle-man. If you can convince a user to visit your site, you have an opportunity to help them engage with your service. The prompt builds on that engagement and lets users who are engaged choose to keep the experience to the homescreen, where it can then launch in a more immersive mode.

Alone, though, this has major drawbacks.

First, users have been trained for the past decade to look for "apps" in App Stores and might not understand the install prompt. This is part learning-curve and part legitimate concern. To the extent that users encounter these prompts and try them out, we just need to wait for time to pass before the App Store expectation is dampened. To the extent that users and developers truly want App Stores, it's possible in the future. More on that below.

Next, in today's Chrome, there isn't any way other than the prompt for the user to understand that the site they're on is an app. If the user rejects the prompt there isn't much the site can do about it. Yes, there's the "Add To Homescreen" menu item, but it doesn't differentiate between plain-old-websites and PWAs in any visual way (despite using PWA metadata if available...very confusing). As a user, I'd love a visual indicator that let me know if sites I'm on are PWAs that I could keep; this is what "ambient badging" (the next section) is about.

Lastly, as Ada noted, developers aren't in control of the prompting timing. This is intentional. In conversation with developers and users, we came to understand 2 things very clearly:

  1. Users bloody hate the web's cesspool of prompts and interstitials. It got so bad that Search finally had to do something about it, marking sites that prompted users who did nothing other than land on a page not mobile-friendly. It's hard to see how an experience like that is anything-friendly, but I digress.
  2. Web developers do not feel as though they are doing anything wrong -- or worse, feel powerless to prevent their businesses from -- prompting users in ways that create horrible experiences.

The predictable result of this situation is that if a browser allowed users to be prompted to add something to the homescreen whenever the developer wanted, the overall experience of using the web would suffer. This isn't academic: we did this wrong with Geolocation and now we're having to walk it back; through pleading, data, and yes, breaking changes. As a team that cares most about users and a healthy web ecosystem, repeating mistakes like this simply isn't acceptable. The predictable result of designing the API the way Ada and others have suggested would be that we'd have to change it later. That change would likely have been of the form "you can call this API all you want, but the prompt isn't going to show until the user has engaged with your site".

What we went with in the end is simply the same thing, but inverted: by doing all the work to make your thing a Progressive Web App, you've signaled to us that you really do want users to keep this thing to their homescreens. If the timing isn't right, Chrome, Samsung Internet, and Opera let you delay the prompt and show it at a time of your chosing later using onbeforeinstallprompt.

Where the prompt design ended up is exactly where it would have come to rest anyhow; we just short-circuited user pain and spammy experiences.

One final point on prompting: the browser controlling when prompts happen was inevitable, but doing it this way has also allowed us to iterate and experiment. Chrome continues to change the engagement heuristic used to trigger the prompt. In the last year it has fallen from requiring 3 navigations with an hour between 2 of them to only requiring that the user scroll and tap while in a site for a few minutes. All of this is a direct response to developer feedback that they'd like the prompt to trigger more often, which we're balancing with user feedback about when and how often they're prompted. We're also watching the rates at which users accept the prompts. A fall in those rates would signal that we're being too aggressive, but thus far we haven't seen a drop.

The net effect, then, has been that PWAs haven't been introduced to users as a way that they can be spammed or which they (in general) resent. This mirrors how we designed Web Notifications: unlike native apps that frequently take the installation step as carte blanche to spam users with notifications, Web Notifications are always opt-in and easily user-controlled. This sort of careful API design that takes the cumulative experience of users into account is what sets the web apart. Unlike other software ecosystems, the web is not predatory by default and we aim to keep it that way while extending its capabilities further.

Ambient Badging

But enough about what we've done; what's next? Ambient badging!

Wouldn't it be great if there were a button in the URL bar that appeared whenever you landed on a PWA that you could always tap to save it to your homescreen? A button that showed up in the top-level UI only when on a PWA? Something that didn't require digging through menus and guessing about "is this thing going to work well when launched from the homescreen?" Such a button/indicator would let us do things like say to friends, colleagues, and customers "to get the Example app, go to and tap the Frobulate button".

This sort of badging doesn't require any engagement from the user; it's a non-invasive signal that says "hey, this is something you can keep!".

We're actively working on ambient badging in Chrome for Android, but I'm honestly surprised that no other browser has beat us to the punch. When combined with prompting, ambient badging solves (or I hope it will solve) the inability to "verb" PWAs, to have a common visual and conversational vocabulary around "keeping" PWAs, and dealing more elegantly with discoverability for developers who feel frustrated by the prompt's capriciousness.

App Stores

App Stores have been part of my thinking around PWAs long before they were called "PWAs". All of the technology that we use for PWAs -- Manifests, Service Workers, and URLs -- are compatible with any store that wants to list them. This, I think, is a major un-tapped area of exploration and it's not exclusionary to ambient badging or engaged-user prompting. It's possible for a browser or platform to implement one, two, or all of these mechanisms in parallel.

Imagine a future version of a desktop OS you use every day. In our ever-more App Store-mediated desktop OSes, it seems natural to go looking for apps to "keep" there. In this sense, App Stores are search engines for "keepable" experiences. PWAs are exactly that: keepable experiences. The meta-data around listing and installation are all available and no separate bundle or package needs to be made. All the app store in question needs to do is to verify that the person listing the app is actually the owner, that the app meets whatever legal guidelines they enforce, and that the site meets the PWA criteria. Most of this is automatable and all of it is possible with the PWA technology we've deployed already. To the extent that changes are necessary to support it, the Manifest spec is explicitly designed to be extensible.

App Stores are another area where I'm surprised that we haven't seen more non-Chrome innovation. Can't wait to see what happens there next. PWAs are great fit for these "keepable experience" search engines.


If PWAs are by-design App Store-compatible -- assuming those stores want to allow them to be listed and "kept" and aren't just pursuing proprietary visions where businesses pay exhorbitantly to re-develop for each platform and form-factor -- then Search engines are the proto-App Store.

It's possible to imagine supporting specially highlighted & badged links that can be opened stand-alone by default if the resulting URL is a PWA...say a separate "open standalone" link next to a result. It's also possible to imagine separate "keep and visit" buttons in search results for URLs that are part of PWAs. Again, this future has been part of my thinking around distribution for PWAs for a long, long time, but it has only relatively recently become possible for crawlers to detect and enforce the quality bar that PWAs set.

Obviously, I have no inside information about what Bing's engineers think the future should look like, but if it seems natural for search engines to list Native Apps (which they do today), then this also seems mighty reasonable.

The Limits of "Keep" Are PWAs Strength

We've got pretty strong data from native app ecosystems that users don't use many apps, uninstall heavily, and in general find installation frustrating and taxing.

What's important about PWAs, then, is that they are OG "streamable apps". Most users won't install most PWAs most of the time, and that's fine. Hoping for more is how the tech industry found itself over-funding a gold rush only to reap the predictable consequences. The notion that native apps are "better" has largely been a self-reenforcing mantra borne of a Silicon Valley monoculture wherein the needs of billions are simply presumed (without investigation) to be the same as the behaviors of VC's kids, nephews/nieces, and close associates.

It's maddening. It's idiotic. But it's also why the web has a shot. Bubbles burst and the web will finally be ready to pick up the slack when this one does.


Older Posts

Newer Posts