Frontend Requirements: Users, Devices and Networks
Turn wishes like 'make it fast' into testable front-end requirements: budgets, browser support, accessibility and states, and see how each shapes the design.
What you'll learn: By the end of this lesson you will be able to explain how front-end requirements differ from back-end ones, write the states of a user interface as requirements, and turn vague wishes into measurable, testable sentences. You will also be able to write a browser-support policy, treat accessibility as a requirement with a named target, choose between progressive enhancement and graceful degradation, and map each requirement to a design consequence you can defend to product and design.
A restaurant kitchen is a controlled place. You choose the stove, the staff and the hours. A shopfront is not. You do not choose whether a customer arrives by car, by bus, in a wheelchair, in the rain, or while carrying three bags and a crying child. If the door is heavy, some customers leave, and none of them tell you why.
A front-end system is the shopfront. The back end is the kitchen. This lesson is about writing down what the shopfront must handle before anyone draws a component.
The running example is an online store with three journeys: a product page, search, and checkout. Every number in the examples is an illustrative assumption, not data from a real store.
The core idea
A front-end requirement describes what a person experiences in a browser, on a device and network you do not own. The back-end requirements lesson covers latency percentiles, availability nines, durability and SLOs for servers you run. Read it for those ideas. Here we use them, but four things change.
The code runs on someone else's machine. The same page may run on a recent laptop, an older phone with little memory, or a browser with extensions that block scripts. You must measure it from the user's browser: field data (data collected from real visits), as opposed to lab data (data from a test you run yourself).
"Fast" is perceived, not computed. A server response of 50 ms means little if the page then spends seconds downloading and running JavaScript. The requirement must describe what the user sees and can do.
The design space is a matrix. Device power, screen size, input method (touch, keyboard, mouse, screen reader), browser, network quality and user preferences all combine.
More people own the result. Designers, product managers, legal, marketing (who add tags and scripts) and several engineering teams all change the page. Requirements also say who may change what.
A useful rule: a front-end requirement is complete when it names a journey, a condition (device, network, browser, user need), a measurable outcome and a way to check it.
Functional requirements of a UI: journeys and states
A user journey is a path through the product that a person takes to reach a goal: find a product, compare two, pay. List the journeys first, in order of business importance. For the store:
Product page: see the product, choose a size, add it to the basket.
Search: type a query, filter results, open a product.
Checkout: confirm the basket, enter an address, pay, see a confirmation.
A back-end feature list usually stops there. A front-end specification must go further, because the screen is never in just one condition. Each piece of data on screen has several states, and each one is a requirement.
State
What the user sees
Requirement question
Loading
Something is on the way
What appears first? Is there a placeholder that holds the layout still?
Empty
A valid request with no results
What does search say when nothing matches? What can the user do next?
Error
The request failed
What is said, in plain words? Can the user retry without losing input?
Partial
Some data arrived, some did not
If reviews fail, does the product page still let me buy?
Offline or slow
The network is gone or poor
What still works? Is the data shown possibly stale, and does it say so?
Success
The normal case
What exact content and actions appear?
The "partial" row is the one teams skip, and it drives real architecture: a page built from five independent data sources can show four of them. A page that treats the five as all-or-nothing turns a failed reviews service into a blank product page.
Figure 1. The states of the search results area
stateDiagram-v2
accTitle: States of the search results area
accDescr: The results area moves from idle to loading, then to results, empty, partial or error, and can show stale results when offline.
[*] --> Idle
Idle --> Loading: user submits query
Loading --> Results: all data arrives
Loading --> Empty: valid query, zero matches
Loading --> Partial: some data fails
Loading --> Error: request fails
Error --> Loading: user retries
Partial --> Loading: user retries
Results --> Stale: network lost
Stale --> Loading: network returns
How to read this: every arrow out of Loading is an outcome the design must handle. "Stale" means showing results already on screen while saying they may be out of date. If a state has no design, it will still happen, and the user will see whatever the code does by accident.
Non-functional requirements, written as testable sentences
A non-functional requirement (NFR) says how well the product must work. The weak form is an adjective ("accessible", "fast", "secure"). The strong form is a sentence a person or a tool can check. A good template:
For [journey], on [condition], [measurable outcome], checked by [method].
The table gives one illustrative sentence per quality. The numbers are assumptions you would replace after measuring.
Quality
Weak wording
Testable sentence (illustrative)
Checked by
Performance
"The product page is fast"
On the product page, the largest content element appears within 2.5 s for 75% of real visits on each of mobile and desktop
Field data, per device class
Responsiveness
"Search feels snappy"
Typing in the search box, filtering and adding to the basket respond visibly within 200 ms for 75% of real visits
Field data
Accessibility
"It is accessible"
Product page, search and checkout conform to WCAG 2.2 Level AA, and a keyboard-only user can complete checkout
Automated checks plus manual review
Browser support
"Works everywhere"
The browsers in the support policy get full function; others get the basic purchase path
Test matrix, browserslist
Network
"Works on bad Wi-Fi"
On a throttled slow connection, the product page shows a price and an add-to-basket button before images load
Lab test with throttling
SEO and previews
"Good for search"
Product pages return their title, price and description in the first HTML response and carry preview metadata
HTML check of the raw response
Internationalisation
"Supports other languages"
The store shows prices, dates and text in the shopper's chosen language and currency, and layouts survive text 40% longer (illustrative)
Pseudo-localisation test
Privacy
"We respect privacy"
No analytics or advertising script runs before the shopper's consent choice
Automated network check
Security
"It is secure"
A Content Security Policy blocks inline and unknown scripts on checkout
Header check in CI
Reliability
"Never fails"
If the reviews service fails, the product page still sells; if payment is slow, an order is never placed twice
Fault-injection test
Maintainability
"Clean code"
A team can change checkout without a release of the product page
Repository and deploy boundaries
Two terms from the table need a definition. Pseudo-localisation replaces text with accented and lengthened fake text to expose layouts that break when translations are longer. A Content Security Policy (CSP) is a rule set, sent as the Content-Security-Policy HTTP response header, that tells the browser which sources of scripts and other resources are allowed. MDN describes it mainly as a defence against cross-site scripting. See security for the server side.
Device and network diversity
You do not need statistics to design for diversity. You need to name the dimensions and decide which ones your product will promise to support. This lesson deliberately does not quote any figure for how many people use which device. Your own field data, from real visits, is the only number that matters for your product.
Figure 2. What a front-end design does and does not control
How to read this: everything on the left is a condition you must design for and cannot fix. Everything on the right is where you can act. Requirements describe the left side; architecture is your response on the right.
Device dimensions: processor speed and memory (which decide how much JavaScript a device can run before it feels stuck); screen size and pixel density; input (touch, mouse, keyboard, voice, switch devices); assistive technology such as screen readers; and user preferences such as larger text, a dark colour scheme, or reduced motion.
Network dimensions: bandwidth, latency (the delay per round trip), packet loss, connection changes mid-session (walking from Wi-Fi to mobile data), metered or capped data, captive portals (a hotel Wi-Fi page that blocks everything until you sign in), and no connection at all.
Browser dimensions: the engine (Chromium-based, Gecko, WebKit), the version, and which platform features exist. Support differs between engines and versions. MDN's compatibility tables for each feature are the reference.
Some APIs let a page ask about the network. The Network Information API exposes navigator.connection, with an effectiveType estimate. At the time of writing, MDN marks it "Limited availability", meaning it is not Baseline (see below), so treat it as an optional enhancement and never as a requirement.
The pattern matters more than the API: ask for the hint if it exists, and make the page correct when it does not.
From a vague wish to a measurable requirement
"Make it fast" is the front-end version of "make it reliable". It cannot be tested, so it cannot be traded off or defended. Use a short procedure.
Figure 3. Turning a wish into a requirement and a budget
flowchart TD
accTitle: Turning a vague wish into a measurable requirement
accDescr: A vague wish is made specific by choosing a journey, a user condition, a metric and a percentile, then a threshold, a budget and a place to enforce it.
W["Wish: make it fast"] --> J["Pick the journey product page, search, checkout"]
J --> C["Pick the condition device class and network"]
C --> M["Pick the metric what the user sees or feels"]
M --> T["Set threshold and percentile for example 75th percentile"]
T --> B["Derive a budget script size, request count"]
B --> E["Enforce it CI check plus field monitoring"]
How to read this: each step removes a degree of vagueness. The wish becomes a requirement after the threshold step, and a budget and an enforcement point make it stay true as the code changes.
Pick user-centred metrics
web.dev defines three Core Web Vitals, with "good" targets assessed at the 75th percentile of page loads, segmented across mobile and desktop:
Largest Contentful Paint (LCP): loading. Good is 2.5 seconds or less.
Interaction to Next Paint (INP): responsiveness. Good is 200 milliseconds or less.
Cumulative Layout Shift (CLS): visual stability, meaning how much content jumps around. Good is 0.1 or less.
These are thresholds published at the time of writing (see the web.dev link below, which is where changes would appear). The Loading Performance and Core Web Vitals lesson explains how each is measured and improved. Here the point is narrower: they give you shared vocabulary for a requirement sentence. You can also add your own metrics, such as the time until the add-to-basket button works.
Note the percentile. A 75th percentile target means one visit in four may be worse. A stricter requirement for checkout, such as the 90th, is a legitimate product decision with a cost.
Turn the metric into a budget
A performance budget, in web.dev's words, is a set of limits imposed on metrics that affect site performance. web.dev describes three kinds: quantity-based (page weight, number of requests, script size, number of fonts), milestone timings (loading and interaction milestones) and rule-based (scores from tools such as Lighthouse). Quantity limits are easy to explain and to check in a build. Timing limits are closer to the user experience. Combine both.
A budget is derived from a requirement. If the product page must show its main image in 2.5 seconds on a slow connection, there is only so much you can download before then. Work backwards from the target, divide it among HTML, CSS, JavaScript, images and fonts, and write the result down. Illustrative budget for the product page:
Resource
Limit (illustrative)
Why
JavaScript needed before first interaction
150 KB compressed
Parse and run cost on weaker phones
Images above the fold
1 hero image, at most 3 requests
Main image decides the loading time
Web fonts
2 files
Each is a request and can shift text
Third-party scripts
0 before consent
Privacy and loading requirement
Enforce the budget where it is cheapest to catch a break. A check in continuous integration (CI) fails the build when a limit is passed, the way a test fails. Field monitoring then catches what a lab test cannot. web.dev names Lighthouse CI among the tools for CI checks.
A browser-support policy
"Support all browsers" is not a policy, because support has a cost and the list must be finite. A browser-support policy states which browsers get the full experience, which get a working basic experience, and which are not tested. Write it as sentences and as a machine-readable query.
For the second part, Browserslist is a shared configuration read by front-end build tools, such as Babel and Autoprefixer, so they know which browsers to target. Its queries are described in its README. A few examples from the README: > 0.5% (browsers above that share of global usage), last 2 versions, not dead (excludes browsers without official support or updates for 24 months), and defaults, which expands to > 0.5%, last 2 versions, Firefox ESR, not dead. Put it in package.json:
That is a usage-based policy. It depends on the Can I Use data bundled with the tool, which you must update from time to time.
A second option is Baseline. web.dev describes Baseline as an indicator of which web platform features are safe to use based on browser support, now defined by the WebDX Community Group. A feature is Baseline Newly available when it works in all browsers of the core set: Chrome (desktop and Android), Edge, Firefox (desktop and Android) and Safari (macOS and iOS). It becomes Baseline Widely available 30 months after that date. Browserslist's README lists queries such as baseline widely available and baseline newly available, so the same idea can drive tooling. Check your installed Browserslist version supports them.
{"browserslist":["baseline widely available"]}
A readable policy for the store, in plain sentences (illustrative):
Full experience: the current and previous major versions of the Baseline core browsers on desktop and mobile.
Basic purchase path: older browsers that still run our basic HTML and CSS. They can search, view a product and check out without enhancements.
Not tested: anything else. We do not block it, we do not promise it.
Review: the policy is checked against field data (which browsers real shoppers use) every quarter, and any change is recorded.
The third point is honest and cheap. The fourth stops the list from freezing while your audience moves.
Accessibility as a requirement
Accessibility means people with a wide range of abilities and circumstances can use the product: low vision, colour blindness, deafness, motor or cognitive differences, a broken arm, bright sunlight, a noisy room. Treating it as a requirement means naming a target and a method, the way you name a performance budget.
The standard to name is the Web Content Accessibility Guidelines (WCAG), published by the W3C. At the time of writing, WCAG 2.2 is the newest version (a W3C Recommendation, first published on 5 October 2023; the current edition is dated 12 December 2024), and the W3C encourages use of the latest version. It does not supersede WCAG 2.0 or 2.1, but content that meets 2.2 also meets those earlier versions, with one exception: 2.2 removes the criterion on parsing (4.1.1), so people required to report on 2.0 or 2.1 may still need to test it. WCAG 3 is an early draft and not something to cite as a target.
WCAG is organised under four principles: perceivable, operable, understandable and robust. Each success criterion (a testable statement) is assigned to one of three conformance levels: A (the minimum), AA and AAA (the highest). The levels are cumulative: AA means all A and AA criteria are met. The W3C's own guidance says Level AAA is not recommended as a general policy for entire sites, because some content cannot meet every AAA criterion.
So a common requirement is "WCAG 2.2 Level AA for the three journeys". Two criteria you can turn into specific tests:
1.4.3 Contrast (Minimum), AA: text needs a contrast ratio of at least 4.5:1, or 3:1 for large text (at least 18 point, or 14 point bold).
2.5.8 Target Size (Minimum), AA: pointer targets need to be at least 24 by 24 CSS pixels unless an exception applies, such as sufficient spacing. This affects buttons on the checkout page.
Automated tools find a limited part of the problems. Keyboard-only checkout, screen-reader labels and focus order need a person to test them. Put both methods in the requirement.
WARNING
Do not turn a WCAG level into a statement about legal compliance. Whether a rule applies to you, and which version or level it expects, depends on your country, your sector and the wording of the regulation. Ask your legal team. This lesson gives engineering requirements, not legal advice.
Progressive enhancement and graceful degradation
Both approaches answer the question "what happens when something is missing?" MDN defines progressive enhancement and graceful degradation as related but pointing in opposite directions.
Progressive enhancement starts with a baseline of essential content and function for as many users as possible, then adds richer experiences for browsers that can run them.
Graceful degradation starts from the full experience and falls back to something less capable, still delivering essential content and function, where features are unavailable.
MDN says both are valid and often complement one another. For a front-end design the practical difference is where you begin. The first suits the primary purchase path, where failure costs money. The second suits an extra, such as an animated product viewer.
Here is progressive enhancement in a search form. Without JavaScript it is an ordinary form that loads a results page. With JavaScript, a script can take over and update the page in place.
<formaction="/search"method="get"id="search-form"><labelfor="q">Search products</label><inputid="q"name="q"type="search"required><buttontype="submit">Search</button></form><divid="results"></div><scripttype="module">const form = document.getElementById("search-form");
form.addEventListener("submit", async (event) => {
event.preventDefault();
const query = newFormData(form).get("q");
const response = awaitfetch(`/search?q=${encodeURIComponent(query)}&partial=1`);
if (!response.ok) { form.submit(); return; } // fall back to the full page loaddocument.getElementById("results").innerHTML = await response.text();
});
</script>
If the script fails to load or the fetch fails, the form still works. The sample assumes the server has a results page at /search and can return a fragment for partial=1; both are part of the design, not given by the browser. Injecting server text with innerHTML is only safe when the server escapes it, a point the security lesson covers.
The same idea applies in CSS. Use a feature query so a browser that lacks a feature keeps working with the plain layout.
A browser that understands display: grid gets the grid; one that does not shows the products in a plain column.
The requirements people forget
Four qualities appear late, and then they are expensive.
SEO and link previews. Search engines differ in how they handle JavaScript. Google says it renders pages with a headless Chromium when resources allow, and still describes server-side or pre-rendering as a great idea, because not all bots can run JavaScript. A link preview (the card shown when a link is pasted into a chat app) is usually built from tags in the <head> of the first HTML response; the Open Graph protocol defines og:title, og:type, og:image and og:url as the required properties. If a requirement says "product pages show a title and image when shared", client-only rendering of those tags will not meet it for crawlers that do not run scripts.
Internationalisation (i18n). Beyond translated text: currency, dates, number formats, text that grows, and right-to-left layouts. The browser's Intl API formats numbers by locale, as in the example below. Retrofitting after the layout is written is far harder than planning for it. WCAG 3.1.1 (level A) also expects the page language to be set with lang on the html element.
Privacy and consent. Requirements such as "no tracking script before consent" shape how third-party scripts load. The rules depend on your jurisdiction, so involve legal early and turn the decision into a testable sentence.
Security. Beyond a CSP, third-party scripts run with the full power of your page. A requirement should say which third parties may run on which pages.
const price = 123456.789;
console.log(newIntl.NumberFormat("en-US", { style: "currency", currency: "USD" }).format(price));
// $123,456.79console.log(newIntl.NumberFormat("de-DE", { style: "currency", currency: "EUR" }).format(price));
// 123.456,79 € (MDN's example; a no-break space separates the number and the sign)
Both lines format the same number; only the locale changes.
How requirements drive architecture
A requirement is useful when you can say what it changes. These are the questions the later lessons answer; this table links each requirement to the design choice it pushes toward, using the store's examples.
Requirement (illustrative)
Design consequence
Trade-off
Product page content visible within 2.5 s on mobile for 75% of visits
Rendering strategy that delivers HTML with content, not an empty shell; small critical script budget
Server or build-time work and cache rules to maintain
Product pages indexable and shareable
HTML includes title, price, description and preview tags in the first response
Less personalisation in cached HTML
Price and stock must not be stale at payment
Cache product description aggressively, never cache the final price check
More API calls on checkout
Basic purchase path works without enhancements
Progressive enhancement: forms that submit by themselves, enhanced by script
Two code paths to test
One team ships checkout independently
Separate route bundles and deploy boundary; shared design system
Duplicated dependencies; versioning of shared parts
Search stays usable on a flaky connection
Show last results with a "may be out of date" label; cancel stale requests
State handling grows more complex
No third-party script before consent
Load analytics after the consent choice; a tag-loading rule in CI
Less marketing data from the first visit
WCAG 2.2 AA for checkout
Semantic HTML first, a tested component library, focus management in the router
Slower custom widgets
Order never placed twice
Unique request key and a "check status" step after a timeout
Needs server support
The Frontend System Design lessons Rendering Strategies and HTTP Caching for the Front End take the rendering and caching consequences in turn. For the server-side view of caching, see caching basics.
Figure 4. A checkout request on an unreliable network
sequenceDiagram
accTitle: Placing an order when the response is lost
accDescr: The shopper presses pay, the page sends one request with a unique key, the response is lost, so the page asks for the order status using the same key and shows the confirmation.
participant S as Shopper
participant P as Checkout page
participant A as Order API
S->>P: press Pay
P->>P: disable button, show progress
P->>A: place order with key K
A-->>A: order created for key K
Note over P,A: response is lost, page times out
P->>S: "Still working, checking your order"
P->>A: status of key K
A-->>P: order exists
P-->>S: confirmation screen
How to read this: the requirement "an order is never placed twice, and the shopper is never left guessing" is met by two choices, one unique key per attempt and a status check instead of a blind second submit.
If the key is meant to prevent duplicates, the server must honour it. That is why front-end requirements often become API requirements; see API design.
Negotiating trade-offs with product and design
Requirements conflict. A marketing carousel wants large images and scripts; the budget wants few. A designer wants a custom date picker; the accessibility target wants native behaviour or a lot of testing. Negotiation goes better with a repeatable approach than with opinions.
State the conflict in user terms. Not "the carousel is heavy" but "with the carousel, the main product image appears later than the target for slower connections".
Show the data. A lab trace, a field metric, or a budget table makes the discussion concrete without personal criticism.
Offer options with costs. For the carousel: show one hero image and load the others on interaction; keep the carousel and raise the budget by dropping another feature; or move it below the fold.
Ask for a decision, record it, set a revisit trigger. The back-end lesson's decision record works here: context, decision, consequences, revisit when.
Protect the non-negotiables. Agree early which requirements are fixed (checkout works on the basic path, AA contrast) and which are budgets that can move.
A budget is a negotiation tool. Because adding something means paying for it with something else, the conversation changes from "can we add this?" to "what do we trade for it?"
In practice: an online store fixes its product page, search and checkout
NOTE
A realistic scenario, not a case history. This is a composite example built from common production patterns. It does not describe any specific company, and every number in it is an illustrative assumption.
The situation
A mid-sized online store sells home goods. A team of five front-end engineers maintains one application that is rendered entirely in the browser: the server returns an almost empty HTML page and a large JavaScript bundle, which then calls product, search and payment APIs. Customer support reports three complaints: the site feels slow on phones, shared product links show a blank preview card, and some mobile shoppers say the Pay button "does nothing". Nobody has written down what the site must do, so each complaint turns into an argument.
Starting architecture
Figure 5. Starting architecture: everything renders in the browser
How to read this: the shopper's phone has to download and run the whole bundle before anything useful appears, and the Pay button depends on a script from a third party loading in time.
Options considered
Option
What it fixes
What it costs
Risk
Optimise inside the current design (split bundles, compress images)
Some loading time
Low
Preview cards and indexing stay broken; no written target
Write requirements first, then change the rendering of product pages only
Loading, previews, indexing for the pages that earn the money
A rendering change and cache rules for product pages
Cached pages can show stale price if rules are wrong
Rewrite everything on a new framework
Possibly everything
Months of work, a long freeze
No agreed target to prove the rewrite helped
The decision
Field
Decision record
Context
Complaints about speed, link previews and a dead Pay button, with no shared definition of "good".
Decision
Write ten requirements (journey, condition, measure, method). Serve product pages as HTML with content and preview tags; keep search in the browser with a server-rendered fallback; keep checkout as a small separate bundle with its own budget and an error state for a failed payment script.
Consequences, good
A written target; previews and indexing work; the purchase path no longer depends on one script.
Consequences, bad
Cache rules for product pages to own; two code paths for search; some marketing scripts must wait for consent.
Revisit when
Field data shows the product-page target missed for two consecutive months, or the support policy for browsers changes.
Rollout and verification
First collect field data for four weeks with no change, so the targets are based on what real visits show rather than a guess. Then add the budget as a CI check that reports but does not block, then blocks. Ship the new product-page rendering to a small share of visits with a feature flag, and compare field metrics and the share of visits that reach checkout. Check the raw HTML response (not the page after scripts run) for title, price and preview tags. Add a fault test that blocks the payment script and confirms the checkout shows the error state with a way forward.
Figure 6. After the change: product pages arrive as HTML, checkout has its own path
How to read this: browsing and buying now take different paths with different budgets. Monitoring watches the real shopper visits so a missed target is seen quickly.
The 2 a.m. failure
The payment provider has an outage in one region. The script that draws the card form never loads, and the Pay button stays disabled. Orders from phones fall sharply. A synthetic check that opens checkout every minute raises an alert: "checkout form not shown within 10 seconds".
First three checks: the payment script request in the browser's network panel (blocked, timing out or returning an error), the checkout funnel in field data (visits that see the form versus visits that submit it), and the provider's status page. Mitigation: switch on the flag that redirects payment to the provider's hosted page, which does not need the script in your page. Follow-up fixes: load the script with a timeout, show an error state with a retry and the hosted-page alternative, and add the "payment script fails" case to the fault tests. The requirement that would have caught it was already in the table: reliability under a failed dependency.
Architect's notes
Write requirements before choosing a framework. A framework choice is an answer. Know the question first.
Decide per journey, not per site. Checkout deserves a tighter budget and a simpler stack than a marketing page. The product page earns the strictest loading target.
Measure in the field. Lab tests catch regressions; field data tells you what users get. Collect it early.
Define the support policy and the baseline path early. The cost of supporting a browser is paid for every feature. A written policy lets you say no calmly.
Treat accessibility as a design input. Retrofitting is slower than starting with semantic HTML and a tested component library.
Defer what you cannot yet measure, such as offline support, until a requirement justifies it. Name an owner for each budget you do set.
Common mistakes
Writing adjectives instead of sentences. "Fast" and "accessible" cannot be tested. Fix: journey, condition, measure, method.
Using the developer's laptop as the reference. It is a fast device on a good network. Fix: pick a device and network class to test, and check field data. Quote a percentile, not an average, as the Core Web Vitals do.
Designing only the success state. Loading, empty, error and partial states are where users get stuck. Fix: list them as requirements.
Promising every browser. It is untestable and costly. Fix: write a support policy and review it.
Treating accessibility as a late audit. Fixes cost more at the end. Fix: name the WCAG version and level at the start.
Letting third-party scripts in unmanaged. Marketing tags can break privacy, security and speed at once. Fix: a budget and an owner for third parties.
Key takeaways
Front-end requirements describe a person on an unknown device and network. You cannot see the conditions from your server, so measure field data.
States are requirements. Loading, empty, error, partial and offline need an explicit design, and partial failure drives architecture.
Write a testable sentence. Journey, condition, measurable outcome, method of checking.
Use user-centred metrics and percentiles. Core Web Vitals give a shared vocabulary, with good targets at the 75th percentile.
A budget turns a target into limits. Quantity, timing and rule-based limits are enforced in CI and watched in the field.
Write a browser-support policy. Use Browserslist and Baseline to express it, and review it against field data.
Name a WCAG version and level. WCAG 2.2 Level AA is a common target, tested by tools and by people. It is not a legal statement.
Start from a working baseline. Progressive enhancement for the purchase path; graceful degradation for extras.
Map each requirement to a design consequence and a trade-off. Then negotiate with product and design using data and options, and record the decision.
Practice exercises
Exercise 1 - Starter (30 min): Take the wishes "the product page should be fast", "checkout should be reliable" and "search should work on bad Wi-Fi". Rewrite each as a sentence using the template (journey, condition, measurable outcome, method). Label every number as illustrative.
Exercise 2 - Intermediate (2 hours): For the store's search results, write a state table with the six states from this lesson: what the user sees and what they can do next in each.
Exercise 3 - Intermediate (2 hours): Write a browser-support policy for a product you know: three tiers in plain sentences and a Browserslist query. Run your query with Browserslist's command-line tool on your machine and list the browsers it selects. Say which entries you would remove and why.
Exercise 4 - Advanced (half day): Choose one page of a site you maintain. Measure its main load metric and its script size, set a requirement and a budget for it, and write a CI step that fails when the script size passes your limit. Then write a one-page note for product and design that proposes one trade-off (for example removing a third-party script) using the negotiation steps.
Within this course, the lessons Frontend System Design: The Big Picture, Rendering Strategies, HTTP Caching for the Front End and Loading Performance and Core Web Vitals continue from the requirements set here.
Lesson 2 of 8 · Frontend System Design Foundations: How the Web Runs
Turn wishes like 'make it fast' into testable front-end requirements: budgets, browser support, accessibility and states, and see how each shapes the design.
In the rest of this lesson
A browser-support policy
Accessibility as a requirement
Progressive enhancement and graceful degradation
The requirements people forget
How requirements drive architecture
Negotiating trade-offs with product and design
Enrolling is free. It unlocks every lesson in Frontend System Design Foundations: How the Web Runs, tracks your progress across devices and keeps your quiz scores. The newsletter is optional.
Real architecture decisions, LLMOps patterns that survive production, and engineering leadership advice — from 12+ years of building at enterprise scale. Free. No spam. Unsubscribe anytime.
Get new articles by email
Free. We email a confirmation link first, and you can unsubscribe from any email.