UX Field Guide
The recurring ideas behind good design decisions — perception, color, type, systems, and process — kept short enough to actually reread before a critique. Pick a topic below.
Condensed Checklist
Every checklist from every topic that has one, in one scannable pass — for a fast design review before a critique, or a last check before shipping. Checks are saved in this browser. (Pure-reference topics like HTML Tags or CSS Properties don't have their own checklist, so they're not listed here.)
Glossary
Every defined term from every topic, gathered in one alphabetical list. Click a term to jump to where it's explained in full.
Gestalt Principles
In 1920s Berlin, a group of psychologists noticed something that still runs every interface built since: the eye doesn't perceive a design element by element — it perceives relationships, and assembles a whole from them before conscious thought catches up. Their word for that whole was Gestalt. Every principle below is a specific rule for how that assembly happens, and each one is something you can point at in a layout and either confirm or violate.
Proximity
Elements placed close together are read as one group, and elements placed apart are read as unrelated — even when every dot is visually identical.
In practice: a form label sits closer to its input than to the next field. A help-icon action row is tighter than the gaps between unrelated sections. Misused when: uniform padding is applied everywhere, so nothing groups and everything competes for attention equally.
Similarity
Shared color, shape, or size groups items into a category, even when they're scattered rather than adjacent.
In practice: all destructive buttons share one color across the whole product, so users learn the color before they read the label. Misused when: a decorative accent color is reused on unrelated elements, teaching users a false grouping.
Closure
Four disconnected corner-marks still read as a square — the eye fills the gap and completes the implied shape.
In practice: a dashed outline or corner brackets can imply a container without the cost of a full solid border. Misused when: a shape is so incomplete the intended form has multiple equally plausible readings.
Continuity
Elements arranged along a line or curve are perceived as a continuous sequence, and the eye keeps following that path past its end.
In practice: a stepper or timeline aligns its nodes on one axis so progress reads as a single path, not isolated dots. Misused when: a sequence bends or staggers with no meaning behind the shift, breaking the implied flow.
Figure-ground
The eye assigns one region the role of "subject" and the other "backdrop." When the split is ambiguous, both regions compete and neither wins.
In practice: a modal dims the page behind it, resolving in half a second which layer is active. Misused when: foreground and background sit at similar contrast, so text seems to float without a clear surface.
Common region
A shared boundary — a card, panel, or tinted background — groups its contents more forcefully than proximity alone can.
In practice: settings are grouped into bordered cards by topic, so scanning the page means scanning card titles, not every row. Misused when: every element gets its own card, and the boundary stops meaning anything.
Common fate
Elements that move, animate, or change state together are perceived as one unit, even if they look nothing alike.
In practice: a drag-reorder lifts the whole row — icon, label, and value — as a single object, confirming what will actually move. Misused when: unrelated elements animate in sync, implying a connection between things that aren't actually linked.
Apply it
- Related controls sit closer to each other than to unrelated ones — check the whitespace, not just the border.
- A consistent visual style (color, shape) is reserved for a single category of thing across the whole product.
- Grouped content sits inside a shared card, border, or background rather than relying on whitespace alone.
- Sequences (steps, timelines, breadcrumbs) sit on one continuous axis, not a staggered or broken one.
- Elevated layers (modals, popovers, tooltips) have enough contrast against the page to read as clearly "in front."
- State changes that belong together animate together, and nothing else moves at the same time.
Color Theory
Color is read before type, before layout, before a single word — it's the fastest-processed signal on a screen, and the easiest one to spend carelessly. Everything here works from one constraint: an interface has to keep working after color is stripped away, calculated, or seen by someone whose eyes process it differently than yours.
Hue is position on this wheel — the "color" itself. Saturation is distance from the center (grey) to the edge (pure color). Lightness is how close a color sits to black or white. Most usable palettes are one or two hues, explored across saturation and lightness — not five different hues at full intensity.
Body text needs 4.5:1 against its background; large text (24px+, or 19px+ bold) and UI components like icons and input borders need 3:1. Check the rendered pixel color, not the token name — a "subtle grey" token can silently fail at small sizes.
A rough starting ratio: most of the screen is neutral (background, surfaces, body text), roughly a third is a secondary supporting tone, and a small slice is the accent — reserved for the one or two things that should draw the eye first. When everything is accented, nothing is.
Roughly 1 in 12 men and 1 in 200 women have some form of color vision deficiency — red-green confusion is the most common. Meaning encoded only in hue disappears for them entirely.
Under the most common form of color blindness, "success green" and "error red" can shift toward the same muddy olive tone. The fix isn't a different pair of hues — it's never relying on hue alone: pair color with an icon, a label, a position, or a shape.
- Pick one neutral family first — with a slight hue bias toward where the accent will sit, not a flat grey. This carries 60%+ of the interface.
- Pick one accent hue tied to the product's actual meaning, not a trend. Define it at 3–4 lightness/saturation steps, not just one value.
- Separately define semantic colors (success, warning, error, info) — never reuse the brand accent for these, even if it happens to look similar.
- Check every text/background pairing you plan to actually ship against WCAG contrast minimums, at real size.
- Test the full palette in grayscale and with a color-blindness simulator before calling it final.
Checklist
- Text and background combinations pass WCAG AA contrast at their actual size.
- Semantic colors (error/success/warning) are reserved and not reused decoratively.
- The palette is built from one or two hues at varied saturation/lightness, not five hues at full strength.
- No meaning is encoded in color alone — every status has a redundant icon, label, or shape.
- The design still communicates correctly viewed in grayscale.
Typography
Type is read thousands of times a day without anyone consciously admiring it — which is exactly why the choices behind it matter. Hierarchy tells the reader what to look at first; scale keeps every screen speaking the same visual language; measure decides whether reading feels effortless or exhausting. All three are systems, not one-off decisions.
Resize this window — every size above is fluid. Try it, then look at the code producing it below.
Fluid type with clamp()
A fixed scale needs a breakpoint for every jump; clamp(min, preferred, max) lets each size interpolate against the viewport instead, so headings scale smoothly from phone to wide desktop without a single media query.
The preferred value does the work: a fixed part (1.2rem) plus a viewport unit (2.5vw) — the fixed part keeps small screens from going too small, the vw term is what actually scales.
Every line break interrupts the eye before it settles into a rhythm — reading feels choppy and slow.
This is close to the sweet spot: the eye can track a full thought per line, and the return sweep back to the left edge is short enough that it doesn't lose its place.
Once a line runs this long, the eye has to travel so far on the return sweep that it frequently lands on the wrong line, forcing the reader to re-scan and re-find their place, which quietly adds up to real fatigue over a long page.
A serif display head
Set against a plain sans body — two distinct voices, one clearly for headlines, one clearly for reading. The eye never has to ask which is which.
A sans display head
Set against a second, very similar sans body — close enough that the difference reads as inconsistency rather than intent, like a typo in the type choice itself.
Checklist
- Every text style on screen maps to a defined step in the type scale — no one-off sizes.
- Heading and content widths scale fluidly with
clamp()rather than jumping at fixed breakpoints. - Body copy sits within the 45–75 character measure at every viewport width.
- No more than two typeface families are in active use, and they're paired by contrast, not similarity.
- Line height is 1.4–1.6× font size for body text, tighter for large display type.
Layout & Visual Hierarchy
Layout is the argument a screen makes before anyone reads a word: what's grouped, what's ordered first, what's safe to ignore. Grids and whitespace aren't decoration on top of that argument — they're how it gets made.
A 12-column grid with a shared gutter. The highlighted 4-column span is one component's footprint — every other component on the page picks a span from the same 12, so unrelated screens still feel like one system.
An 8px-based scale (4/8/12/16/24/32/48/64) covers nearly every real spacing need. Picking from this set instead of arbitrary pixel values is what makes density feel intentional instead of accidental.
Left: each line starts at a slightly different point — reads as unintentional even though every line is individually fine. Right: one consistent left edge. The content hasn't changed; the alignment is the entire difference.
Eye-tracking studies find text-heavy pages get scanned in a roughly F-shaped path — two horizontal sweeps, then a vertical drop down the left edge. Sparser, image-led pages get scanned in a Z — put the logo top-left, the primary action bottom-right, and the eye will cross it on the way down.
Show what's needed for the current decision; defer the rest to an explicit action — an expandable row, a second step, an "advanced" toggle — instead of laying every option out at once. It trades a small amount of extra clicking for a much smaller amount of clutter on first view, which is almost always the right trade for anything used repeatedly.
Checklist
- Every component's width maps to a span on the page's shared grid, not an arbitrary size.
- Spacing values come from a defined scale (e.g. 4/8px steps), not arbitrary pixels.
- Elements align to a consistent edge within their group — check by drawing an imaginary line down the left side.
- The single most important action on the screen sits on the page's natural scan path.
- Secondary detail is deferred behind a clear, discoverable action rather than shown by default.
Cognitive Psychology for UX
These aren't design opinions — they're findings from experimental psychology, most of them decades old, that happen to predict how people behave in front of a screen. Treat them as constraints on the brain doing the reading, not style preferences to argue about.
RT = a + b · log₂(n)
Decision time grows with the logarithm of the number of choices — so going from 2 options to 4 hurts about as much as going from 4 to 8. Doubling the choice count, not adding a fixed number, is what costs time.
In practice: a settings page splits into categories instead of one long list, so each individual decision faces fewer options. Misused when: options are hidden purely to look minimal, forcing extra clicks to even see what's available — Hick's Law is about choices at one moment, not total feature count.
MT = a + b · log₂(D / W + 1)
Time to reach a target rises with the distance to it (D) and falls as its width (W) grows. A large, close target is fast to hit; a small, far one is slow and error-prone.
In practice: a screen edge or corner is effectively infinite width in one direction (the cursor can't overshoot past it) — that's why OS menus and taskbars live there. Misused when: a frequent action (like a mobile "close" button) is rendered as a tiny tap target far from the thumb's natural resting position.
7 ± 2 items
Working memory holds roughly seven discrete items at once — but "item" is flexible: grouping (chunking) several small pieces into one meaningful unit lets people hold far more effective information than the raw count suggests.
In practice: a 12-digit account number is easier to hold onto split into four groups of three than as one unbroken string — same digits, far less load. Misused when: a long form is broken into steps just to look shorter, without the steps mapping to any real grouping in the content.
Jakob's Law
Users spend most of their time on other products, and bring those expectations with them — a cart icon, a hamburger menu, a swipe-to-delete gesture all carry meaning before they're even used here. Deviating from convention has to buy something, or it's just a tax on relearning.
Cognitive load
Every unfamiliar term, inconsistent pattern, or unclear next step draws down a shared, limited budget of attention. It's spent whether or not the interface intends to spend it — the only choice is spending it deliberately on what matters, or losing it to friction.
Recognition over recall
Recognizing something in a list is far easier than retrieving it from memory unprompted. A dropdown of past values beats an empty field asking someone to remember what they typed last time.
Apply it
- Menus and choice sets are split into fewer, categorized groups rather than one long flat list.
- Primary actions are large and positioned within easy reach of the likely cursor or thumb position.
- Frequent targets are pushed to edges and corners where they gain effectively infinite width.
- Long sequences (numbers, steps, lists) are chunked into groups of roughly 3–5 rather than left unbroken.
- Familiar conventions (icon meanings, nav placement, gestures) are followed unless there's a strong, specific reason to deviate.
- Previously entered or common values are shown as options, not left to memory.
Design Systems
A design system is what lets a hundred screens, built by a dozen different people over several years, still feel like one product. It works by moving decisions upstream — instead of re-deciding "what shade of red" every time someone builds an error state, that decision gets made once and referenced everywhere.
space.4 · radius.md
Card · Alert
Settings page
Raw values become named tokens; tokens compose into components; components assemble into the patterns end users actually experience. Each tier only depends on the one before it — a component never hardcodes a color, it references a token, so a token update propagates everywhere at once.
| Token | Value | Used for |
|---|---|---|
color.accent.500 | #2B6E68 | Primary buttons, links, active states |
color.danger.500 | #C0392B | Destructive actions, error text |
space.4 | 16px | Default gap between related fields |
radius.md | 8px | Cards, inputs, buttons |
font.size.body | 1rem | Default paragraph and label text |
A token's name should describe its role (color.danger.500), not its raw value (red) — the name is what stays stable if the underlying hex ever changes.
| Syntax | Example | Use |
|---|---|---|
| Declare | --color-danger-500: #c0392b; | Any selector can declare a custom property — :root for global tokens, a class for a scoped override. |
| Read | color: var(--color-danger-500); | Reads the nearest declared value up the cascade — same inheritance rules as any other CSS property. |
| Fallback | var(--gap, 16px) | Used if the custom property isn't defined at all — not if it's defined as an empty or invalid value. |
| Scoped override | .card--danger { --card-accent: var(--color-danger-500); } | Redeclaring a token inside a component's scope changes it there without touching the global value. |
This is the token tier from a token sheet made literal: color.danger.500 from the table above becomes --color-danger-500, and every component's CSS reads it through var() instead of a hardcoded hex. See CSS Properties Reference for the property syntax itself.
- Custom properties vs. preprocessor variablesA Sass
$variableis resolved once at build time and produces static CSS — a custom property is resolved live in the browser, so it can change at runtime (media query, JS, class toggle) without a rebuild. - Theming (dark mode)Redeclare the same token names under a different scope —
[data-theme="dark"] { --surface: #1a1a1a; }— every component that readsvar(--surface)re-themes automatically, no per-component dark-mode logic. - Component-level tokensA component can expose its own custom properties (
--button-radius) that default to a global token but can be overridden per-instance — a public API for one-off tweaks that doesn't require a new utility class. - Read/write from JavaScript
el.style.setProperty('--progress', '60%')— the standard bridge for data-driven CSS (a progress bar's fill, a drag position) without touching inline styles for everything else.
color.danger.500backgroundspace.3vertical,space.5horizontal paddingradius.mdcorners- States: default, hover, focus-visible, disabled, loading
- Documented usage rule: one destructive action per view
A component isn't just its visual spec — it's the spec plus every state it can be in, plus the rule for when it's the right component to reach for at all. Skipping the states is the most common reason systems drift: someone needs a "disabled" look, can't find one documented, and invents their own.
- Audit existing screens and extract the color, type, and spacing values actually in use — not the values you wish were in use.
- Consolidate near-duplicates into a single token set before naming anything (that "5 shades of grey" is usually 2 in disguise).
- Build the 5–10 components used most often first — buttons, inputs, cards — not the full library up front.
- Document every state (default, hover, focus, disabled, error, loading) alongside each component, not just the default look.
- Assign an owner and a lightweight contribution process — a system with no owner drifts back into inconsistency within a quarter.
Checklist
- Every color, spacing, and type value in the product traces back to a named token, not a raw hardcoded value.
- Each component's states (hover, focus, disabled, error, loading) are documented, not improvised per screen.
- Token names describe role ("danger"), not appearance ("red") — so the name survives a rebrand.
- The system has a named owner and a defined way to propose a change.
- Tokens are implemented as CSS custom properties (
var(--token)), not hardcoded values duplicated per component.
Heuristics & Checklists
Jakob Nielsen published these ten in 1994 as a fast way to catch usability problems without running a full study — read them as a lens to hold up to an existing screen, not a spec to design from scratch.
Visibility of system status
The system always shows what's happening, within a reasonable time — a user should never wonder whether their click registered.
Match between system and the real world
Words, concepts, and metaphors match the user's world and vocabulary, not internal system or engineering terms.
User control and freedom
People make mistakes; a clearly marked "emergency exit" lets them leave an unwanted state without a lengthy process.
Consistency and standards
The same word, icon, or action means the same thing everywhere in the product — and follows platform conventions.
Error prevention
Better than a good error message is a design that prevents the error from happening in the first place.
Recognition rather than recall
Minimize memory load by keeping objects, actions, and options visible, instead of requiring recall from an earlier screen.
Flexibility and efficiency of use
Accelerators — shortcuts, saved views, batch actions — speed up experts without adding clutter for novices.
Aesthetic and minimalist design
Interfaces shouldn't contain information that's irrelevant or rarely needed — every extra unit competes with the relevant ones.
Help users recognize, diagnose, and recover from errors
Error messages are expressed in plain language, precisely indicate the problem, and suggest a solution.
Help and documentation
Ideally the system needs no explanation — but when it does, help should be easy to search, task-focused, and concrete.
A visible focus ring is the only way a keyboard-only user can tell where they are on the page. Removing it for aesthetics (a bare outline: none) is one of the single most common accessibility regressions — replace it with a deliberate style, never delete it outright.
Accessibility quick-check
- Every interactive element is reachable and operable by keyboard alone, in a logical tab order.
- Focus states are visible on every focusable element — never suppressed without a replacement.
- Images carry meaningful alt text; purely decorative images are marked as such (empty alt).
- Color contrast meets WCAG AA at actual use size for text and meaningful UI components.
- Form fields have associated
<label>elements, not placeholder text alone. - Interactive elements have accessible names that describe their action, not just an icon.
Interaction Patterns
Most products are built from the same handful of recurring moments — filling a form, finding a place, waiting for something, or arriving at nothing. These are the ones worth getting right on purpose, because they repeat everywhere and get noticed most when they're missing.
Focused — validation waits until blur, not every keystroke.
Enter a complete email address, like name@example.com.
Labels sit above the field (never placeholder-only — placeholders disappear the moment someone starts typing). Validation runs on blur, not per keystroke, so a half-typed email isn't flagged as wrong while it's still being written. The error message names the fix, not just the failure.
No projects yet
Projects you create will show up here, along with their status and last activity.
A blank list looks broken even when it's correct. A real empty state does three things: confirms nothing is wrong, explains what will eventually appear, and offers the one action that gets the user out of it.
A skeleton mirrors the shape of the content that's about to arrive, so the layout doesn't jump when it does — better than a spinner for anything with a known structure. Reserve spinners for short, genuinely indeterminate waits, and never leave a screen simply frozen with no feedback at all.
More patterns
- NavigationCurrent location is always visible (active state, breadcrumb); depth stays to 2–3 levels before users lose their place.
- FeedbackEvery action gets an immediate, proportional response — a click always visibly does something within ~100ms.
- Destructive actionsGated by confirmation or backed by an easy undo — never a single accidental click from data loss.
Checklist
- Every destructive action has a confirmation step or an easy undo.
- Empty, error, and loading states are all explicitly designed — none defaults to a blank screen.
- Form validation runs on blur, not on every keystroke, and names the field and the fix.
- Labels are persistent (above or beside the field), never placeholder text alone.
- Loading states mirror the shape of the incoming content wherever that shape is predictable.
UX Writing
Every label, button, and error message is a small promise about what will happen next. Good UX writing keeps that promise in as few words as possible; bad UX writing is often the single largest source of a product feeling untrustworthy, independent of how it looks.
Under stress or time pressure, a reader scans for the fact, not the personality. Voice can still come through in word choice and rhythm — it just can't cost the reader an extra beat to decode what happened.
Name things by what a person is trying to do, not by the internal object the engineering team built to do it. If the audience is developers, technical language is their language — the rule is "speak the reader's vocabulary," not "always simplify."
A button should answer "what happens if I press this?" without requiring the surrounding context. "OK" answers nothing on its own.
A good error message states what went wrong and exactly what to do about it, in that order, with no apology filler ("Oops! Sorry about that!") standing between the reader and the fix.
Checklist
- Every button label states the resulting action, not a vague verb like "submit" or "ok."
- Terminology names things the way the audience already thinks about them, not internal system objects.
- Error messages explain the cause and the fix, with no blame or apology filler.
- One word is used per concept throughout — no alternating "remove" / "delete" for the same action.
- The most important word in any label or notification comes first, not buried mid-sentence.
Research & Information Architecture
Research is how a design's assumptions get tested against what people actually do, rather than what a team hopes they'll do. Information architecture is what happens after — organizing what's been learned into a structure other people can navigate without help.
Research without a goal behind it produces interesting trivia, not decisions — the goal is what turns a finding into a "so what."
- The goal is a business outcome (revenue, retention, signups, support-ticket volume), not a design activity — "redesign the checkout flow" is a task, not a goal.
- It's specific and measurable, with a number and a timeframe attached — "improve conversion" isn't testable; "increase checkout completion 10% by Q3" is.
- It's tied to a metric someone already tracks, or a plan exists to start tracking it, before research begins — not invented after the fact to justify a finding.
- The business goal and the design goal are stated separately and linked explicitly — e.g. business goal: increase signups 15%; design goal: reduce signup-form friction, as the team's bet on how to get there.
- Background — why this project, why now; the context a new team member would otherwise have to ask about.
- Objective — the business goal above, restated as what this specific project is meant to move.
- Audience — who this is for, in enough detail to separate "everyone" into an actual primary user.
- Scope & constraints — what's explicitly in and out, plus any technical, brand, or timeline constraints already known.
- Success criteria — how the team will know it worked, stated before work starts, not chosen afterward to fit the result.
- Timeline & stakeholders — key dates and who has approval authority at each one.
A brief is a shared reference the team returns to when a decision gets contested, not a document written once and archived — it should be short enough that people actually reread it.
Concept feedback sessions
Preference / desirability studies
Contextual inquiry
A/B testing
Attitudinal methods capture what people say; behavioral methods capture what they actually do — the two frequently disagree, which is exactly why both matter. Qualitative explains the "why" in depth from a few people; quantitative confirms the "how many" at scale. Pick the quadrant that matches the question being asked, not the method that's most familiar.
- User interviewsOpen-ended, task-anchored questions — ask what someone actually did last time, not what they'd hypothetically do.
- Usability testing5 users typically surface roughly 85% of major usability issues in a given flow — depth over sample size for this method.
- Card sortingParticipants group and label content themselves, revealing the mental model to design navigation around.
- Tree testingTests a proposed navigation structure in plain text, isolating findability from visual design as a confound.
- SurveysGood for scale and prioritization across a large group; weak on its own for uncovering the "why" behind behavior.
- Goals & motivationsWhat the person is trying to accomplish, and why it matters to them — the part that actually drives design decisions.
- BehaviorsReal patterns pulled from interviews, usability sessions, or analytics — not demographics standing in for behavior. Age and job title rarely predict how someone uses a product.
- Pain points & frustrationsSpecific, sourced friction — vague enough to feel true and pass without scrutiny is a warning sign, not a finding.
- A representative quoteAn actual line from research, not an invented one — it keeps the persona anchored to a real person's words instead of the team's assumptions.
A persona built from a stakeholder's guess about "our typical user" is fiction with a stock photo attached — it should synthesize research that already happened, not substitute for research that didn't.
- User flowScreen-to-screen paths and decision points through one task — answers "what are the steps, and where do people branch or drop off."
- Journey mapStages, actions, thoughts, and emotions across a longer experience (often spanning outside the product) — answers "where does this feel worst, and why."
- Service blueprintA journey map plus what happens behind the scenes (systems, teams, handoffs) to support each front-stage step — answers "what breaks operationally when this scales."
Each diagram answers a different question — a flow diagram won't reveal an emotional low point, and a journey map won't show where a form's validation logic breaks. Pick the one that matches what's actually being decided.
- Profile — name, photo, contact info
- Billing — plan, payment method, invoices
- Notifications
- Email preferences
- Push preferences
- Security — password, sessions, 2FA
A healthy tree stays shallow (2–3 levels) and every item has exactly one clear home — "Notifications" doesn't also make sense under "Security." When card sorting produces two equally plausible parents for the same item, that's a signal the categories themselves need rethinking, not that the item is unusual.
Checklist
- The research method matches the actual question — attitudinal vs. behavioral, qualitative vs. quantitative.
- Interview questions ask about specific past behavior, not hypothetical future preference.
- Every IA category has a clear, non-overlapping definition — one home per item.
- Labels use the audience's own vocabulary, validated by card sorting where possible.
- Navigation depth stays shallow — breadth over depth in most cases.
- The structure is tested with real tasks (tree testing or a live prototype) before being treated as final.
User Stories & Red Routes
Personas and research answer "who, and what do they need" — user stories turn that into something a team can actually build, and red routes answer the next question: of everything on the backlog, what absolutely cannot break.
As a [persona], I want to [action], so that [benefit].
The format forces three things into one sentence that are easy to skip individually: who this is for, what they're actually trying to do, and why — the "so that" clause is what stops a story from becoming a disconnected feature request. A story with no persona attached, or a persona that's really "the user" standing in for everyone, hasn't done its job.
- IndependentCan be built and shipped without waiting on another story — a backlog of tangled dependencies can't be reprioritized on the fly.
- NegotiableA story is a placeholder for a conversation, not a locked spec — the details get worked out with the team before build, not dictated in advance.
- ValuableDelivers something a real persona cares about — "refactor the internal API" isn't a user story; frame the user-facing outcome that justifies it instead.
- EstimableThe team can size it — if nobody can estimate it, it's usually too vague or too large to be one story.
- SmallFits inside a single iteration — a story that spans multiple sprints is really an epic wearing a story's clothes.
- TestableHas a clear pass/fail — if there's no way to verify it's done, "done" will get argued about later instead of checked.
Together these are the INVEST criteria — a fast filter for whether a story is actually ready to build, not just written down.
The specific, testable conditions a story has to meet before it counts as done — written before build starts, agreed by whoever's building it and whoever's asking for it, so "done" isn't negotiated after the fact.
A Given / When / Then structure (an invalid input state / a user action / the resulting system behavior) is the fastest way to make a criterion checkable instead of debatable.
The small set of journeys that matter most to the business and to users at the same time — the ones where a usability problem doesn't just annoy someone, it costs a conversion, a renewal, or trust in the product outright. Not every path through a product is a red route; most products only have a handful.
- High frequencyDone often, by a large share of users — a rarely-used path can be broken longer without much real-world cost.
- High importanceDirectly tied to a core business or user outcome — checkout, sign-up, the action the product exists to enable.
- Low tolerance for frictionUsers have the least patience here, and the highest expectation that it "just works" — this is where a rough edge does the most damage.
A route qualifying on frequency or importance alone is worth watching; qualifying on both is what makes it red — those are the journeys that get dedicated usability testing, get regression-tested before every release, and get first claim on a fix when something breaks.
- List candidate journeys — pull from analytics (highest-traffic paths), support tickets (what people get stuck on), and the core business goal (what the product is actually for).
- Score frequency and importance — even a rough high/medium/low per journey is enough to separate the obvious red routes from the long tail.
- Cut the list down — a "red routes" list of twenty items has stopped functioning as a priority list; keep it to the handful that would actually justify emergency attention if broken.
- Revisit after major changes — a new feature or pricing change can promote a previously minor path to a red route, or retire one that used to matter.
Checklist
- Every story names a specific persona — not "the user" standing in for everyone.
- Stories pass the INVEST test before entering a sprint, not after it stalls mid-build.
- Acceptance criteria are written and agreed before build starts, in a testable Given/When/Then form.
- Red routes are identified from real data (analytics, support tickets), not gut feeling about what seems important.
- The red-route list stays short enough to actually drive priority — a handful of journeys, not the whole sitemap.
- Red routes get dedicated usability testing and regression checks before every release that touches them.
Accessibility
Accessibility isn't a separate feature bolted onto a finished design — it's what happens when semantic structure, keyboard support, and clear contrast are treated as requirements from the start, the same as "the button has to work." Heuristics & Checklists (07) has a fast pre-ship pass; this is the reference behind it.
- PerceivableContent can be perceived through more than one sense — text alternatives for images, captions for video, sufficient color contrast, content that doesn't rely on color alone to convey meaning.
- OperableEvery interaction works by keyboard as well as pointer, with no time limit a user can't extend, and no content that flashes in a way known to trigger seizures.
- UnderstandableText is readable, pages behave predictably (navigation doesn't move or change unannounced), and errors are identified with help correcting them.
- RobustContent works with current and future assistive technology — valid, semantic markup that a screen reader can parse reliably, not just a browser.
These are the four organizing principles behind WCAG. Almost every specific rule below is really just one of these four applied to a particular kind of element.
A native <button> is keyboard-focusable, triggers on both Enter and Space, and announces its role to a screen reader automatically — a styled <div> gets none of that for free, and re-implementing it by hand (tabindex, keydown handlers, ARIA role) is easy to get subtly wrong. The rule of thumb: reach for the native element before reaching for ARIA on a generic one.
Landmark elements (<header>, <nav>, <main>, <aside>, <footer>) let screen reader users jump straight to a page region instead of tabbing through everything above it — see HTML Tags Reference for the full element set.
- Don't use ARIA if a native element already does the job —
<button>beats<div role="button">every time. - Don't change native semantics unless you really have to — putting
role="heading"on a<button>confuses more than it clarifies. - All interactive ARIA controls must be keyboard-operable — adding a role without keyboard support makes it visible to assistive tech but unusable through it.
- Don't use
role="presentation"oraria-hidden="true"on a focusable element — it hides the element from assistive tech while leaving it reachable by keyboard, an inconsistent state. - All interactive elements need an accessible name — visible label,
aria-label, oraria-labelledby; an icon-only button with none announces only as "button."
ARIA changes what assistive technology announces — it changes nothing about visual appearance or default behavior. It's a bridge for the cases plain HTML can't cover on its own (a custom combobox, a live region), not a general-purpose styling or behavior tool.
- Every interactive element is reachable via Tab, in an order that matches the visual reading order.
- Focus is visible at all times — see the focus-ring demo in Heuristics & Checklists.
- A modal or dialog traps focus while open, and returns it to the triggering element on close.
- No keyboard trap exists outside an intentional one — a user can always Tab or Escape their way out.
- Custom widgets (dropdowns, tabs, sliders) follow the expected key pattern for that widget type (e.g. arrow keys inside a tab list), not just Tab and Enter.
- Alt textDescribes the image's purpose in context, not its literal contents — a logo linking home gets alt="Acme home," not "blue triangle logo." Purely decorative images get an empty
alt=""so a screen reader skips them entirely. - Form labelsEvery input has a real
<label>tied to it viafor/id— placeholder text disappears the moment someone starts typing, so it can't substitute for a label. - Live regions
aria-live="polite"on a container announces content that changes without a page reload (a toast, an inline validation message) to a screen reader user who isn't looking at that part of the screen. - Heading structureOne
<h1>per page, and heading levels used for document outline, not font size — a screen reader user often navigates a page heading-by-heading, and a skipped level (h2 straight to h4) breaks that map.
Testing checklist
- Navigate the whole flow using only the keyboard — no mouse — and confirm nothing is unreachable or trapped.
- Run an automated scan (axe, Lighthouse, WAVE) to catch the easy mechanical issues — contrast, missing labels, invalid ARIA — but treat it as a floor, not a full audit.
- Test with a real screen reader (VoiceOver, NVDA, or JAWS) on at least the red routes — see User Stories & Red Routes.
- Zoom the page to 200% and confirm content reflows without loss of function or horizontal scroll on the main content.
- Color contrast meets WCAG AA — see the contrast reference in Color Theory.
Ideation & Sketching
The point of a sketching session isn't to produce a finished idea — it's to get a lot of bad ideas out fast, cheaply, where changing direction costs a marker stroke instead of a rebuilt component.
- Frame the problem — one specific question the session is meant to answer, written where everyone can see it. A vague prompt produces vague sketches.
- Diverge alone first — a few minutes of silent individual sketching (e.g. "Crazy 8s": 8 ideas in 8 minutes) before any group discussion, so the loudest voice in the room doesn't anchor everyone else's ideas.
- Share without defending — each person walks through their sketches; the group listens and captures reactions, doesn't argue merits yet.
- Converge deliberately — dot-voting or a simple ranking narrows the full set down to the few ideas worth developing further, based on the framed problem, not personal preference.
- Develop the survivors — the winning idea(s) get a more detailed sketch or storyboard, the bridge to wireframing.
Collapsing diverge and converge into one step — sketch and critique simultaneously — is the most common way a session quietly turns into everyone re-drawing the first idea someone said out loud.
- Crazy 8sFold a page into 8 panels, one idea per panel, 8 minutes total — forces quantity over polish, which surfaces the odd idea that a single careful sketch never would.
- How Might WeReframes a problem as an open question ("How might we reduce signup abandonment?") — phrased to invite many answers, not just the one already in mind.
- StoryboardingA short sequence of panels showing a user moving through a scenario — good for surfacing a flow's context (before/after the product, not just the screens themselves).
- Design studioMultiple rounds of individual sketch → group critique → refine, run rapidly — treats a first idea as a draft to iterate live, not a proposal to defend.
- A relevant, cross-functional group is in the room — not just design; the people who'll build and support the idea catch different problems early.
- Low-fidelity materials only (markers, paper, whiteboard) — polish this early reads as "finished," which shuts down critique prematurely.
- A visible timer keeps each round moving — open-ended sketching time tends to expand to fill the room's patience, not the problem's needs.
- Quiet individual work happens before group discussion, every round — not just once at the start.
- The session ends with a concrete next step (a sketch to wireframe, a question to test) — not just a pile of paper nobody owns.
Ethical, Inclusive & Sustainable Design
Three separate lenses, easy to conflate but answering different questions: is this honest, does it work for people who aren't like the team that built it, and what does it cost beyond the screen.
- Dark patternsInterface choices engineered to make a user do something they wouldn't choose if the option were presented plainly — a pre-checked "add insurance," a cancel flow buried six steps deep. If a pattern only works because someone doesn't notice it, that's the signal it's dark.
- Honest defaultsA default should reflect what's genuinely best for most users, not what's most profitable for the business at the user's expense — the two aren't always in conflict, but when they are, the default reveals which one won.
- Consent that means somethingA real choice has a genuinely easy "no" — a consent flow with one prominent "Accept" and a tiny, low-contrast "manage preferences" link isn't offering a real choice.
- Data minimalismCollect what the feature actually needs, not what might be useful someday — every extra field collected is a liability the user didn't agree to in any meaningful sense.
- Recognize exclusionEvery design decision includes some people and excludes others, often invisibly to the team making it — the first step is noticing the exclusion exists, not assuming a "neutral" design has none.
- Solve for one, extend to manyDesigning for a specific permanent, situational, or temporary constraint (one-handed use, a broken arm, low light) frequently improves the product for everyone — captions help a phone on silent in a meeting, not just d/Deaf users.
- Diverse perspectives, genuinely presentA team's own lived experience is a narrow sample of the eventual audience — inclusive design requires input from people outside that sample, not just good intentions from within it.
- Beyond WCAGAccessibility compliance (see Accessibility) is the enforceable floor; inclusive design is the broader practice of designing for difference in language, culture, literacy, and ability that compliance alone doesn't capture.
- Digital carbon footprintEvery page load, image, and server request has an energy cost — a heavier page isn't free just because nothing physical was manufactured.
- Performance as sustainabilityOptimized images, minimal third-party scripts, and efficient code reduce both load time and energy use at the same time — the sustainability case and the UX case for performance are usually the same case.
- Designing for longevityA product built to be maintained and extended, not rewritten from scratch every few years, avoids the resource cost of full rebuilds — durability is itself a sustainability decision.
- Nudging greener behaviorWhere the product touches a real-world choice (shipping speed, print vs. digital, device replacement), a default or prompt toward the lower-impact option is a legitimate design lever, not just a policy one.
Checklist
- No interface pattern relies on a user not noticing it to work — reversed, that's still a legitimate design.
- Consent and cancellation flows are at least as easy as the sign-up or opt-in flow they mirror.
- The design has been reviewed by, or tested with, people outside the team's own demographic and ability range.
- Page weight and third-party scripts are actively minimized, not left to grow unchecked release over release.
Micro-interactions & Motion
A micro-interaction is a single task done in one moment — toggling a setting, liking a post, pulling to refresh. Motion is what makes that moment legible: not decoration, but the thing that shows what just changed and why.
- TriggerWhat starts the interaction — a user action (tap a toggle) or a system condition (a background sync completes). Every micro-interaction has exactly one.
- RulesWhat happens once triggered — the logic determining what can and can't happen next (a toggle can only be on or off; a like can't go negative).
- FeedbackWhat the user sees, hears, or feels confirming the rules ran — the toggle slides and changes color, a heart briefly scales up. This is where motion does its job.
- Loop & modesDoes it repeat, and does its behavior change with repetition or context — a "like" the tenth time behaves the same as the first, but a rate-limited action might not.
Missing feedback is the most common failure — the rules ran correctly (the setting did save) but nothing on screen confirmed it, so the user re-triggers the action, unsure whether the first attempt worked at all.
- Spatial continuityAn element that transforms into the next screen (a card expanding into a detail view) tells the eye where it went — a hard cut between two unrelated layouts forces the user to reorient from scratch.
- Easing over linearReal objects accelerate and decelerate; linear motion (constant speed start to finish) reads as mechanical and draws attention to itself instead of the content moving.
- Duration matched to distance and frequencyA small, frequent transition (a toggle) should be fast (~100–200ms); a large, rare one (a full-screen modal) can afford to be slower — the same duration on both makes one feel sluggish or the other feel jarring.
prefers-reduced-motionSome users get real physical discomfort (vestibular disorders) from large or fast motion — respecting this media query by removing or reducing non-essential motion isn't optional polish, it's an accessibility requirement.
- Every state-changing action has visible feedback — nothing relies on the user just trusting it worked.
- Motion clarifies a spatial or causal relationship (this became that) rather than just adding movement for its own sake.
- Duration and easing are matched to the size and frequency of what's moving, not a single value reused everywhere.
prefers-reduced-motionis respected — see Media & Container Queries for the query syntax.- A micro-interaction used often (a like, a toggle) stays fast enough that the animation is never the bottleneck to the next action.
KPIs & A/B Testing
A KPI stated after the fact tends to be whichever number went up. Stated before build starts, it's a commitment the team can actually be judged against — and the thing an A/B test is designed to move on purpose.
- Tied to the business goalThe same business-goal-to-design-goal link from Research & IA — a KPI that can't be traced back to a business outcome is a vanity number.
- A single primary metricOne north star per initiative, with a small set of guardrail metrics watched alongside it (so the primary metric can't improve by quietly breaking something else).
- Leading vs. laggingA lagging metric (churn, revenue) confirms success late; a leading metric (activation rate, feature adoption) predicts it early enough to still act on. Track both, weight decisions toward the leading one.
- A number and a timeframe"Increase trial-to-paid conversion from 12% to 16% within one quarter" is testable. "Improve conversion" is a hope.
- State the hypothesis first — "Changing X will cause metric Y to move because Z" — not "let's just try a version and see." A test without a stated reason can't teach you anything when it's wrong.
- Pick one primary metric to decide the test — with guardrails to catch an unintended regression elsewhere, decided before launch so results can't be cherry-picked after the fact.
- Size the sample before running it — estimate the traffic and duration needed to detect a meaningful effect; a test stopped early on a promising-looking trend is usually just noise.
- Run for full business cycles — at minimum full weeks, to average out day-of-week effects (weekday behavior often differs sharply from weekend behavior).
- Ship, iterate, or kill — explicitly — a test that "sort of" won doesn't get shipped by default; the pre-stated significance and effect-size bar decides, not enthusiasm for the idea.
Checklist
- The KPI is stated with a number and a timeframe, before the project starts — not selected afterward to match the result.
- A single primary metric decides the test; guardrail metrics are watched but don't drive the ship decision alone.
- Sample size and test duration are calculated ahead of time, not eyeballed as "long enough" mid-flight.
- The hypothesis is written down before the test launches, in a form that could turn out to be wrong.
Website Process
The design principles above only pay off inside a process that gets the right information at the right time. This is the practitioner side — how a website project actually moves from a sales conversation to a live, supported site, and what each stage needs from the client to avoid rework later.
What "the website" is actually made of, useful for setting expectations with non-technical stakeholders.
The same lifecycle, condensed to five words — organize, design, code, launch, grow.
A representative week-by-week timeline — actual duration scales with project scope, but the phase order (brand → build → launch → grow) holds.
Every stage builds on a signed-off deliverable from the one before it — sitemap before wireframes, wireframes before design comps, design before build. Skipping a sign-off to save time almost always costs more time later, in the form of rework.
A working version of the stage-by-stage process, on a real week scale. The two sides are separate timelines that happen to share that scale, not one merged list: client-facing deliverables (left) are grouped and snapped to week-end, since that's the cadence the client actually experiences; agency checkpoints (right) run on their own finer-grained internal schedule. The gridlines are what let you read them against each other.
The full stage-by-stage process, as diagrammed for client-facing proposals — this tracker is the interactive version. Download the static graphic (PNG)
Discovery happens twice: a lightweight pre-proposal questionnaire to size the quote, then a deeper kickoff questionnaire once the project is signed. Both exist to move assumptions out of people's heads and onto paper before design starts.
- Pre-proposalCompany background, current site/hosting status, rough sitemap sketch, must-have features, and top 3 goals — enough to size hours, not enough to design from.
- Kickoff questionnaireRevisits goals in depth, reviews/updates the sitemap section by section, and captures competitors, differentiators, and a short list of descriptive adjectives for tone.
- Kickoff meetingHeld face-to-face or live where possible — personality and tone come through faster in conversation than in a form. One point of contact or small decision group is confirmed here.
- Mood board exerciseA shared reference board (e.g. Pinterest) for likes/dislikes — cheaper to disagree about references now than about finished comps later.
Content is the most common source of schedule slippage on a website project — treating it as a planned deliverable, not an afterthought, is what keeps development on schedule.
- Sitemap is broken into sections, and each section into its actual pages, before any copy is drafted.
- Every page is broken into its content modules (e.g. header, subtitle, description, call to action) so copywriting and layout can happen in parallel.
- Who is writing first-draft copy — client or copywriter add-on — is decided before the build phase starts, not during it.
- Existing photography/video assets are inventoried early; gaps become a scoped add-on (photography, video, stock) rather than a late surprise.
Hosting and a domain's DNS records are separate things that get confused constantly: DNS is the directory that points a domain name at a server; the web server is what actually stores and serves the site's files. Full DNS record reference, hosting-tier comparison (shared, managed, VPS, dedicated, cloud, static/JAMstack), and a migration checklist now live in their own topic — Hosting & DNS (26) — this card stays as the short version for the process walkthrough.
- Static / low-traffic sitesLightest tier — a simple site with at most one basic form, low traffic.
- CMS-driven sitesStandard tier for sites with a content management system and typical traffic.
- CustomScoped individually — e-commerce, high traffic, or unusual infrastructure needs.
Hosting support typically covers performance tuning and minor fixes after a browser update (capped at a small number of hours per year, e.g. under 2), not ongoing content edits — that's a separate updates/support line item. Support access is usually a defined business-hours window (e.g. weekdays, 8am–5pm) via phone and email, not 24/7.
- Research — keyword research, competitor research, link research, and a pass on the existing user experience.
- Implementation — on-page tags (titles, meta descriptions, alt text, schema), image/page speed optimization, clean URL and code structure.
- Optimization — re-crawl and review after implementation; ongoing keyword relevance and internal linking.
- Outreach — link building, guest posts, reclaiming lost or broken backlinks.
- Analysis — report against organic traffic growth, not raw keyword rank alone.
A site's SEO sits inside a larger ecosystem — content, search, and social all feed each other rather than working in isolation.
A full SEO pass produces two report types: an SEO audit (tagging, page speed, code structure, sitemap/schema health) and a website audit (UX and infrastructure), plus supporting analyses — analytics, keyword, competitor, backlink, and business-listing (Google Business Profile and similar) — each pointed at a specific question rather than run for its own sake.
Sales — detail
The sales stage, one level deeper: what actually gets asked and scoped before a contract is signed.
- Business & goals — mission and core values, who the customers are, what the business provides, project goals, what information matters most to communicate.
- Problem questions — what isn't working today, what problems the project should solve, what customers struggle with, what a good outcome looks like.
- Solutions walkthrough — the client's digital ecosystem today, the proposed future solution, and the process overview so expectations are set on how work actually happens.
- Next steps — what happens between this meeting and a signed proposal.
Discovery questions, in full
Business & goals
- What is your mission / core values / purpose?
- Who are your customers?
- What does your business do or provide for customers?
- What are your goals with this project?
- What information do you feel is important to communicate with your customers?
Problem questions
- What is not working?
- What problems do you hope to solve?
- What are some challenges your customers face?
- What do you hope customers will gain with the solution?
Additional services
Named explicitly during discovery, rather than assumed to be included in the base scope:
- Website updates & supportRequested updates completed within an agreed turnaround (e.g. one week) — a worry-free way to keep the site current without an in-house developer.
- SEO support & consultingOngoing management of SEO tasks plus consulting, run as an extension of the client's own team.
- Email hosting & managementProfessional email at the business's own domain, billed per account per year.
- CopywritingAdditional written content to fill out remaining content areas, when messaging/creative concepts are needed.
- Custom photo & video creationPersonalized photography/video, typically delivered through a third-party vendor — either managed directly or recommended.
- Stock assetsStock photos/video to fill content gaps — treated as a gap-filler, not a long-term content solution.
- Graphic designBranding and digital graphics for online and traditional advertising, presentations, and brochures, kept consistent across mediums.
Brand discovery (when a logo/brand is in scope)
A separate, deeper meeting than the business discovery above — run when the client needs a logo or brand identity, not just a website.
- Company infoFounding story, short- and long-term goals, where the brand needs to grow.
- Target audienceWho the ideal user is, their demographics, a day in their life, what they struggle with and want.
- Brand personality & perceptionClient rates the brand across personality-trait scales and picks descriptive words — including words for what the brand is not.
- Brand message & valuesCore values behind decisions, and how those values should show up in the logo/identity.
- USP & competitive analysisWhat sets the company apart, who the real competitors are, and where they fall short.
- Logo discoveryColor/symbol preferences, then a forced choice between logo formats and styles to narrow direction before design starts.
Brand discovery deck
A 35-slide client-facing deck to run the meeting above: fill-in templates and visual exercises the client reacts to in the room, with facilitation notes on every slide.
- BusinessWorkshop agenda, one-page snapshot, north-star goal and pre-mortem, 1/5/10-year roadmap, interview guide, brand audit.
- Market & audienceCompetitor table, positioning map, SWOT, audience map, persona, empathy map, discovery channels, customer journey.
- BrandGolden Circle platform, personality sliders, word bank, archetypes, USP, positioning statement, messaging pyramid.
- Logo & visualAffinities, palette and type reactions, logo formats and styles, moodboard directions, then success metrics and next steps.
Logo formats
- Word markRelies entirely on typography — no symbols or graphics. Font choice, color, spacing, and letter arrangement alone carry the identity.
- Pictorial markStraightforward imagery or symbols that tell the brand's story through pictures, simply and directly.
- Abstract markGeometric and non-literal — doesn't depict a real object, so it represents the business more conceptually, adding a layer of interpretation.
- EmblemThe company's name or initials set inside a pictorial shape, as one unified mark — tends to evoke tradition, authority, and heritage.
Logo styles
- ContemporaryFresh colors, stylized imagery, clean type, often geometric — reads as modern, innovative, simple, and efficient.
- ClassicTimeless elements — elegant typography, emblematic symbols, refined imagery — reading as sophisticated, trustworthy, and reliable.
- Detailed / stylizedTwo variants: timeless colors with literal imagery and traditional type (elegant, intricate); or a hand-drawn aesthetic depicting scenes or characters as visual storytelling.
The quote a client sees is a price, but it's built from an hours-based estimate underneath — worth understanding even if the number is all that gets shared.
- Base hours, by stage — discover, plan, design, development, and launch each get their own line items (e.g. kickoff, IA/sitemap, wireframes, design comps, front-end build, responsive work, CMS integration, hosting/DNS setup, training), estimated individually rather than as one lump build number.
- Other / add-on hours — anything outside the base scope (custom pages, animation, e-commerce features, etc.) is estimated separately as "how many × hours per item," so add-ons scale predictably instead of being guessed at.
- Project management overhead — added as a percentage on top of production hours, not estimated task-by-task, since PM effort scales with total project size rather than any single deliverable.
- Hours → cost — total estimated hours × the hourly rate gives a base cost; that base cost is then checked against what the market/client relationship can actually bear, and the gap between the two is a conscious decision, not an accident.
The same hours-based structure carries past the quote into project accounting — hours logged per team member are reconciled against hours estimated, so scope creep shows up as a widening gap rather than a surprise at the end.
Technical scope gets defined during sales, not discovered during build — it's what the proposal actually prices.
- Browser supportLatest two major versions of each supported browser; older-version functionality isn't guaranteed. Wider support is estimated as additional scope.
- Responsive breakpointsFour standard breakpoints — desktop (landscape), tablet, large phone, small phone (portrait). Additional breakpoints are additional scope.
- Accessibility baselineWCAG 2.0 by default; higher levels are estimated separately.
The SEO approach, in three words: optimize digital assets and properties for search, create content the target audience is actually searching for, then promote that content across paid/owned channels — see the fuller 5-phase framework above.
Beyond SEO itself, ongoing digital presence work follows a recurring audit → plan → act cycle rather than a one-time engagement.
- Initial auditUX review, SEO audit, competitor analysis, and an infrastructure check (DNS/CMS/backend) before any plan is proposed.
- Reactive updatesClient-requested edits, completed on a retainer within an agreed turnaround (e.g. one week).
- Proactive updatesThe team monitors the business and suggests updates as things change, rather than waiting to be asked.
- Review cadenceA recurring (e.g. quarterly) report-and-review meeting: performance since last review, recommended changes, goals for the next period.
Tracked activity typically spans four areas: site behavior (page views, clicks, events, goals), content (keyword usage, page structure, tags), competitors (what they're publishing, ranking for, and linking to), and digital presence beyond the site itself (reviews, business-listing accuracy, backlinks, mentions).
- Introduction — the problem being solved and what the new site needs to accomplish.
- Who we are — the team, relevant experience.
- Our process — the same stage overview from the top of this page, shown to the client directly.
- Past work examples — relevant portfolio pieces.
- Management — how the engagement runs day to day.
- Content development — who provides written/visual content, plus optional add-ons (copywriting, custom photography, videography, stock, graphic design) named explicitly so they aren't assumed to be included.
- Browser & device support — restates the scope decisions from 11.1.2 in client-facing language.
- Pricing summary — one-time fees and recurring fees listed separately, with the hourly rate for out-of-scope work stated up front so overages aren't a surprise later.
Start — detail
Once the proposal is signed, the kickoff meeting replaces assumptions with specifics before any design work begins.
- Decision makersOne point of contact or small group with final say — identified before the meeting, not during it.
- Elevator pitchA tight summary of the business, so the team isn't designing against a moving target.
- Print materialsExisting brochures/print design signal tone, style, and color even when a formal brand guide doesn't exist.
- Competition & inspirationReal competitors (and why they work), plus sites the client admires for reasons beyond their own industry.
- Special requestsFunctionality wishlist surfaced explicitly — what looks small can be a large build, and vice versa.
- PersonalityBest captured face-to-face; the client picks descriptive adjectives that carry into copy and design.
- UniquenessThe client's own list of what makes them different — a starting point for messaging, not the final copy.
- About the company — services, long-term goals, named competitors, differentiators, 3–5 descriptive adjectives, primary target market.
- Website goals — top 3 goals, secondary goals, unsolved problems, preferred contact method.
- Website structure — review the existing sitemap section by section, then record the updated version.
- Website content, page by page — what to highlight per page, whether sections can be consolidated, and any page-specific functionality (e.g. how often a listing updates, what a form needs to capture).
- Design mood board exercise — a shared reference board reviewed together for likes/dislikes, plus which existing websites appeal to the client and why.
Discover — detail
Turning the agreed sitemap into an actual content-writing template — the deliverable that content planning (above) points to.
- Section — a group of related pages; carries its own writer directions/notes
- Page — e.g. Welcome, Services, About Us, Contact
- Header
- Subtitle
- Description
- Page — e.g. Welcome, Services, About Us, Contact
Every page is pre-broken into the same three fields before writing starts, so copywriting and layout can move in parallel instead of layout waiting on finished copy.
Checklist
- A single decision-maker or small decision group is identified before kickoff — not a large open committee.
- Discovery captures top goals, competitors, and a rough sitemap before any quote is built.
- Sitemap and wireframes are signed off before visual design starts — structure locked before style.
- Content responsibility (client-drafted vs. copywriting add-on) is settled early — content is usually the real bottleneck.
- Hosting tier, browser/device support, and accessibility baseline (e.g. WCAG 2.0+) are stated in scope, not assumed.
- Launch includes basic SEO setup, analytics tracking, and a recorded training session before handoff.
How the Internet Works
The plain-language mental model behind the process in the previous topic — what content actually is, how it becomes a website, how people find and engage with it, and how all of it fits together as one system to manage.
Everything downstream — the website, search visibility, social presence — is built from the same raw material: photo, video & sound, documents & text, contact information, and customer feedback. A digital brand is really just this content, organized and distributed.
Photography
Podcast
Plain text
Web pages
Addresses
Hours of operation
Social activity
Community involvement
Content rolls up into a web page, pages roll up into a website, and the website's architecture (its sitemap) is what search engines ultimately index and rank.
Yahoo & more
Building the site itself follows its own short loop: organize the content, design around it, code it, launch it, then grow it — grow feeds back into organizing more content, which is why this is a cycle, not a one-time project.
The same content categories also feed social media, news, and community platforms — each a different place people spend time and engage. Paid promotion (the $ inputs) accelerates reach on any of these channels; it doesn't replace having the content in the first place.
Yahoo & more
Original graphic, for comparison — remove once the rebuild above is approved.
A search engine matches what people search for against related content it already knows about, using an algorithm that weighs the same content types (images, video, documents) alongside business-listing data (phone, address, ratings) to decide what's relevant.
When a search is made, the searcher is looking for results that fall into a few categories. These categories of content are what search engines look for when scanning your digital properties.
Original graphic, for comparison — remove once the rebuild above is approved.
Search engines, the website, brand communication & engagement (social/news/communities), and advertising aren't separate efforts — they're four interconnected parts of one ecosystem, each feeding traffic and signal to the others.
Yahoo & more
search ads,
display ads
Original graphic, for comparison — remove once the rebuild above is approved.
Traffic into the website comes from two directions: organic (communicate & engage, search — paid for mostly in time) and advertising (social ads, search ads, display ads — paid for mostly in money). Managing the ecosystem means deciding, deliberately, how much of each you're spending and where.
Yahoo & more
Original graphic, for comparison — remove once the rebuild above is approved.
"You want to be where your customers and potential customers spend time, so you can communicate and engage with them in a positive way." That's the whole model in one sentence — everything above is just the mechanics of doing it well.
Hosting & DNS
Hosting and DNS get confused constantly because they're both invisible when working and both blamed for the same symptom ("the site is down") when they're not. DNS is the directory that points a domain name at a server; hosting is the server that actually stores and serves the site's files.
A domain's DNS records live with a registrar or DNS provider, not with the host — pointing a domain at a new host means updating records where the domain is managed, not "moving" anything at the host itself.
| Record | Example | Use |
|---|---|---|
A | example.com → 192.0.2.10 | Points a domain (or subdomain) straight at a server's IPv4 address — the most common record for pointing a domain at a host. |
AAAA | example.com → 2001:db8::1 | Same as A, for an IPv6 address. |
CNAME | www.example.com → example.com | Aliases one hostname to another — common for pointing www at the root domain, or a subdomain at a third-party service. |
MX | example.com → mail.provider.com (priority 10) | Routes email for the domain to a mail server — unrelated to where the website itself is hosted, and easy to accidentally break when moving hosts. |
TXT | v=spf1 include:_spf.provider.com ~all | Free-text record used for domain verification and email authentication (SPF, DKIM, DMARC) — no direct effect on the site, but breaking it can send outbound mail to spam. |
NS | example.com → ns1.registrar.com | Declares which nameservers are authoritative for the domain — the record that actually determines who controls the rest of the records. |
TTL (time to live) controls how long a record is cached before a resolver rechecks it — lowering TTL a day or two before a planned change (e.g. to 300 seconds) makes that change take effect faster once it's made; propagation can otherwise take up to 24–48 hours as caches around the internet expire on their own schedule.
- Shared hostingMany sites share one server's resources. Cheapest option; a traffic spike or misbehaving neighbor site on the same server can degrade performance for everyone on it. Fine for low-traffic brochure sites, wrong for anything business-critical.
- Managed hostingThe host handles server admin — updates, security patches, backups, uptime monitoring — on top of shared or VPS-level resources. The default recommendation for most client sites: less to maintain, faster support when something breaks, at a price premium over unmanaged shared hosting.
- VPS (virtual private server)A dedicated slice of a physical server's resources, isolated from other tenants. More control and predictable performance than shared hosting, but server administration (OS patches, security) is usually the client's or agency's responsibility unless it's also managed.
- Dedicated serverAn entire physical machine, used by one client only. Maximum control and performance headroom; the cost and administrative overhead to match — reserved for genuinely high-traffic or compliance-driven cases.
- Cloud / serverless hostingResources scale elastically with demand (e.g. traffic spikes) rather than being fixed to one server, and billing follows actual usage. Good fit for unpredictable or seasonal traffic; can surprise a client with a variable bill if usage isn't monitored.
- Static / JAMstack hostingPre-built files served directly from a CDN, with no server-side application running per request. Fast and cheap to host, and a natural fit for a site with no CMS or server-side logic — the "static / low-traffic" tier below usually lives here.
- Static / low-traffic sitesLightest tier — a simple site with at most one basic form, low traffic. Static/JAMstack or basic shared hosting both fit.
- CMS-driven sitesStandard tier for sites with a content management system and typical traffic — managed hosting is the usual default here, since CMS platforms need ongoing patching.
- CustomScoped individually — e-commerce, high traffic, or unusual infrastructure needs typically push into VPS, dedicated, or cloud territory.
Hosting support typically covers performance tuning and minor fixes after a browser update (capped at a small number of hours per year, e.g. under 2), not ongoing content edits — that's a separate updates/support line item. Support access is usually a defined business-hours window (e.g. weekdays, 8am–5pm) via phone and email, not 24/7.
Checklist
- DNS records are documented (registrar, current A/CNAME/MX/TXT values) before any host migration begins.
- TTL is lowered ahead of a planned DNS change, and restored to a normal value once the change has propagated.
- MX and TXT (SPF/DKIM/DMARC) records are explicitly carried over during a host or DNS-provider migration — email is the most common casualty of a rushed cutover.
- The hosting tier matches the site's actual traffic and update needs, not the cheapest option by default.
- Backup frequency and restore process are confirmed, not assumed, before launch.
Online Marketing
Once content exists, it needs somewhere to live. These are the channels a business fully owns (no ad spend, no algorithm rental) — what to publish on each, and the metrics that actually indicate whether it's working.
| Channel | Content types | Target KPIs | Metrics to check |
|---|---|---|---|
| Website | Pillar pages, product/landing pages, release notes, product descriptions, success stories, gated content (ebooks, white papers, templates, checklists) | Brand awareness, lead generation, conversions | Traffic, rankings, bounce rate, time on page, dwell time, pages/session, traffic sources, content downloads, conversion rate, domain authority, backlinks |
| Blog | Blog posts, infographics, long-read guides, case studies | Brand awareness, user engagement, lead generation, conversions | Traffic, rankings, time on page, dwell time, in-blog banner clicks, conversion rate, exit rate, shares, comments, backlinks |
| Email & newsletters | Digests/newsletters, release notifications, webinar invites & recaps, surveys, special offers | Lead nurturing, user engagement, conversions | Open rate, click-through rate, click-to-open rate, unsubscribe rate |
| Social, video & podcast profiles | Product-update posts, content/event promotion, educational or entertaining posts, community engagement posts, influencer takeovers, videos, podcast episodes | Brand awareness, user engagement, lead generation | Likes/upvotes, comments, shares, follower growth, click-through to site, content downloads/registrations from social, views, plays |
Every channel is judged by a different KPI set on purpose — a blog post succeeding on shares doesn't mean an email succeeding on the same measure; match the metric to what that channel is actually for.
SEO, SEM, social, and social media marketing are often lumped together as "digital marketing" — each is actually a distinct discipline with its own sub-tactics.
SEO splits into on-site work (attracting search engines directly, e.g. tags, structure, content) and off-site work (earning word-of-mouth signals, e.g. backlinks, mentions) — both aimed at the same goal: delivering relevant results to users in search engines.
Where SEO earns placement, SEM buys it — pay-per-click and banner ads, both used to deliver relevant results to users in search engines faster than organic ranking alone.
Zoomed out, website management, SEO management, social management, and digital advertising all wrap around the same discover → plan → design → build → launch → grow lifecycle, driving toward the same two outcomes: conversions and sales. An analyse → report → adjust loop runs underneath the whole system, continuously.
A plan starts with a small set of inputs — search/social ad targets, suggested spend and platforms, and a content-creation plan — then runs the same create → report → maintain loop on a recurring cadence.
A representative weekly/monthly cadence: create the social plan → update social profiles to current → run ads against posts → improve content for posts → retarget customers → adjust ads and targeting → research new campaign ideas, then repeat.
A recurring marketing plan is typically line-itemed by discipline, each priced and scoped separately rather than sold as one bundle:
- Website optimizationWebsite management and on-site SEO, billed as a standing monthly line item.
- Search engine marketingPaid ads that attract customers to the website — scoped and quoted per campaign, not bundled into the base retainer.
- Social managementCreating posts and managing customer interactions on social platforms.
- Social media marketingPaid boosts to posts and ads, layered on top of organic social management.
Rates vary by scope and aren't reproduced here — the reusable part is the line-item structure itself, priced per engagement.
HTML Tags Reference
Every standard HTML element, alphabetically, with a one-line description. Tags that are meaningless on their own — a <td> outside a <table>, an <option> outside a <select> — are grouped into a single row with the parent they only work inside of, so the relationship is visible instead of implied. Elements marked deprecated still appear in old code but shouldn't be used in new work.
| Tag(s) | Use |
|---|---|
<a> | A hyperlink — the only tag that natively navigates. |
<abbr> | An abbreviation; the title attribute holds the expansion, shown on hover. |
<acronym> | Deprecated — use <abbr> instead. |
<address> | Contact information for the nearest ancestor <article> or the page. |
<article> | Self-contained content that could stand alone — a post, a card, a comment. |
<aside> | Content tangential to the main flow — sidebars, pull quotes, related links. |
<audio> / <video> | Native audio/video players with controls. Only work together with a nested <source> (one or more alternate files) and optionally a <track> (captions/subtitles) — neither child tag means anything outside these two parents. |
<b> | Bold text with no extra semantic importance — a stylistic offset. |
<base> | Sets the base URL that all relative links on the page resolve against. |
<bdi> | Isolates text that might render in a different direction (LTR/RTL) than its surroundings. |
<bdo> | Explicitly overrides the text direction of its content. |
<blockquote> | An extended quotation, typically indented; add cite for the source URL. |
<body> | The visible content of the page — one per document. |
<br> | A single line break — no closing tag; not for spacing between paragraphs. |
<button> | A clickable control — type="submit" · "reset" · "button". |
<canvas> | A blank drawing surface, rendered via JavaScript — for charts, games, generated graphics. |
<center> | Deprecated — use CSS text-align/margin instead. |
<cite> | The title of a referenced creative work — a book, article, film. |
<code> | A short fragment of computer code, inline. |
<colgroup> / <col> | Only meaningful together — <colgroup> groups a table's columns, and each nested <col> applies styling to one column without touching every cell in it. |
<data> | Wraps content with a machine-readable value via the value attribute. |
<datalist> | A list of suggested autocomplete values, linked to an <input> via its list attribute. |
<del> | Deleted text — shown struck-through by default. |
<details> / <summary> | A native disclosure widget — the <summary> is the always-visible label; it's not valid outside a <details>, which in turn needs it as the click target. |
<dfn> | Marks the defining instance of a term, the first time it's introduced. |
<dialog> | A native modal or non-modal dialog box, shown/hidden via JavaScript. |
<div> | A generic block container with no semantic meaning — the fallback when no other tag fits. |
<dl> / <dt> / <dd> | A description list — the outer <dl> is empty without pairs of <dt> (term) and <dd> (definition), and neither inner tag is valid outside a <dl>. |
<em> | Stress emphasis — rendered italic, carries semantic weight (unlike <i>). |
<embed> | Embeds an external resource (e.g. a PDF or plugin) via the browser. |
<fieldset> / <legend> | Groups related form fields under a shared caption — the <legend> only has meaning as the first child of a <fieldset>. |
<figure> / <figcaption> | Self-contained media (image, chart, code) with an optional caption — <figcaption> is only valid inside a <figure>. |
<font> | Deprecated — use CSS font-family/font-size/color instead. |
<footer> | Closing info for a page or section — copyright, links, contact. |
<form> | Wraps a group of inputs meant to be submitted together. |
<frame> / <frameset> | Deprecated, and only ever worked as this same pair — use <iframe> instead. |
<h1>–<h6> | Heading levels — one <h1> per page, no skipped levels, used for outline not size. |
<head> | Non-visible metadata about the document — title, meta tags, linked assets. |
<header> | Intro or navigation for a page or section — usually logo, title, nav. |
<hgroup> | Groups a heading with its subheading(s) as one outline entry. |
<hr> | A thematic break between sections of content — no closing tag. |
<html> | The root element of the page. |
<i> | Italic text with no extra semantic importance — e.g. a technical term or ship name. |
<iframe> | Embeds another HTML document inline — maps, videos, third-party widgets. |
<img> | An embedded image; needs alt text for accessibility. |
<input> | A single form field — type varies via the type attribute (text · email · password · checkbox · radio · date · file …). |
<ins> | Inserted text — shown underlined by default. |
<kbd> | Keyboard input the user is meant to type. |
<label> | The persistent text tied to a form field via for/id — required for accessible forms. |
<link> | Links an external resource — most commonly a stylesheet or favicon. |
<main> | The page's primary content — one per page, skips repeated chrome. |
<map> / <area> | Defines clickable regions over an <img> — each <area> is one region and is not valid outside a <map>. |
<mark> | Highlighted text, relevant to the current context (e.g. a search match). |
<marquee> | Deprecated/non-standard — use CSS animation instead. |
<menu> | A list of commands or options, styled like <ul> by default. |
<meta> | Metadata like charset, viewport, and description — no closing tag. |
<meter> | A scalar value within a known range — e.g. disk usage, a rating. |
<nav> | A block of primary navigation links. |
<noscript> | Fallback content shown when JavaScript is disabled. |
<object> / <param> | Embeds an external resource via a plugin or fallback content — each <param> passes one setting and is only valid inside <object>. |
<output> | The result of a calculation, tied to the inputs that produced it. |
<p> | A paragraph of text. |
<picture> / <source> | Serves different image files by viewport size or format — one or more <source> options nested inside, falling back to a required <img>. (<source> is reused inside <audio>/<video> for the same purpose.) |
<pre> | Preformatted text — preserves whitespace and line breaks exactly as written. |
<progress> | Progress toward completion of a task. |
<q> | A short, inline quotation — browsers add quotation marks automatically. |
<ruby> / <rt> / <rp> | East Asian pronunciation annotations — only function as a set: <ruby> wraps the base text, <rt> holds the annotation, <rp> supplies fallback parentheses for browsers without ruby support. |
<s> | Text that's no longer accurate or relevant — rendered struck-through. |
<samp> | Sample output from a computer program. |
<script> | Embedded or linked JavaScript. |
<section> | A thematic grouping of content, usually with its own heading. |
<select> / <option> / <optgroup> | A dropdown list — <option> (a single choice) and <optgroup> (a labeled cluster of options) are both meaningless outside a <select> (or, for <option>, a <datalist>). |
<slot> | A placeholder inside a web component where consumer-supplied markup gets inserted. |
<small> | Fine print — disclaimers, legal text, side comments. |
<span> | A generic inline container with no semantic meaning — for styling a run of text. |
<strike> | Deprecated — use <s> or <del> instead. |
<strong> | Strong importance — rendered bold, carries semantic weight (unlike <b>). |
<style> | Embedded CSS rules for the document. |
<sub> | Subscript text. |
<sup> | Superscript text. |
<svg> | Inline vector graphics — scales losslessly and is stylable with CSS. |
<table> / <caption> / <thead> / <tbody> / <tfoot> / <tr> / <th> / <td> | The full table family — none of the row, cell, or grouping tags are valid outside a <table>: <caption> titles it, <thead>/<tbody>/<tfoot> group its rows, <tr> is one row, and <th>/<td> are its header/data cells. |
<template> | Inert markup held for later cloning via JavaScript — never rendered as-is. |
<textarea> | A multi-line text input. |
<time> | A date/time, machine-readable via the datetime attribute. |
<title> | The document's title, shown in the browser tab and search results. |
<tt> | Deprecated — use <code> or CSS font-family: monospace instead. |
<u> | Text with a non-textual annotation, rendered underlined — e.g. a proper name or a misspelling flag. |
<ul> / <ol> / <li> | Unordered and ordered lists — <li> is a single item and isn't valid outside one of these two parents. |
<var> | A variable in a mathematical expression or programming context. |
<wbr> | An optional line-break point inside a long word or URL. |
More terms
- Void elementA tag with no closing tag or children by spec —
<img>,<br>,<input>,<hr>,<meta>,<link>. - data-* attributeA custom attribute like
data-id="42"for storing element-specific data JavaScript or CSS can read — never invents new standard attributes. - ARIA attribute
role,aria-label,aria-hidden, etc. — supplements semantics for assistive technology when native HTML alone doesn't convey them.
CSS Properties Reference
Common CSS properties, alphabetically, with typical values and what each one does — a flat A–Z list for a quick scan or Ctrl+F, rather than hunting through grouped categories.
| Property | Common values | Use |
|---|---|---|
align-items | flex-start · center · stretch | Alignment along the cross axis of a flex/grid container. |
align-self | auto · center · flex-end | Overrides align-items for a single flex/grid child. |
animation | spin 1s linear infinite | Shorthand that runs a named @keyframes sequence. |
aspect-ratio | 16 / 9 · 1 | Locks a box's height to its width by a stated ratio. |
background-color | #fff · transparent | Fill color behind an element's content and padding. |
background-image | url(...) · linear-gradient(...) | An image or gradient layered behind the content. |
background-position | center · top left · 50% 50% | Where a background image is anchored within its element. |
background-size | cover · contain · 100% 100% | How a background image is scaled within its element. |
border | 1px solid #ddd | Shorthand for width, style, and color of an element's edge. |
border-radius | 4px · 50% | Corner rounding — 50% on an equal-side box makes a circle. |
box-shadow | 0 2px 8px rgba(0,0,0,.15) | Drop shadow — offset-x, offset-y, blur, color; inset flips it inward. |
box-sizing | content-box · border-box | border-box includes padding/border in the stated width — the near-universal default. |
clear | left · right · none · both | Pushes an element below any floated neighbors. |
color | #111 · rgb() · var(--ink) | Text color. |
column-gap | 8px · 1rem | Horizontal spacing between flex/grid children. |
cursor | pointer · default · not-allowed | The mouse cursor shown when hovering the element. |
display | block · inline · inline-block · flex · grid · none | How an element participates in layout. |
flex | 1 · 0 1 auto · none | Shorthand for a flex child's grow, shrink, and basis. |
flex-direction | row · column · row-reverse | The axis flex children lay out along. |
flex-wrap | nowrap · wrap | Whether flex children wrap onto new lines when they run out of room. |
float | left · right · none | Legacy text-wrap layout — mostly superseded by flex/grid outside of wrapping text around media. |
font-family | "Inter", sans-serif | Typeface stack, most-preferred first, generic fallback last. |
font-size | 16px · 1rem · 1.25em | Text size — prefer rem so it scales with user font-size settings. |
font-style | normal · italic | Upright vs. slanted glyph style. |
font-weight | 400 · 600 · 700 | Stroke weight; needs a matching font file to actually render. |
gap | 8px · 1rem · 8px 16px | Shorthand for space between flex/grid children — row value first, then column. |
grid-column | span 2 · 1 / 3 | Places a grid child across specific column tracks. |
grid-row | span 2 · 1 / 3 | Places a grid child across specific row tracks. |
grid-template-columns | repeat(3, 1fr) · 200px 1fr | Defines a grid container's column tracks. |
grid-template-rows | auto · repeat(2, 100px) | Defines a grid container's row tracks. |
height | auto · 100% · 320px | Explicit height of an element's content box. |
inset | 0 · 8px | Shorthand for top/right/bottom/left together, on a positioned element. |
justify-content | flex-start · center · space-between | Alignment along the main axis of a flex/grid container. |
letter-spacing | normal · 0.02em | Space between characters — small negative values tighten large display type. |
line-height | 1.5 · 24px | Vertical space per line — unitless values scale with font-size. |
margin | 0 · 8px · 1rem 2rem · auto | Shorthand for space outside an element's border, 1–4 values (top / right / bottom / left). |
margin-top / -right / -bottom / -left | 0 · 8px · -4px | Sets one side's margin individually — negative values pull an element beyond its box. |
max-height | 0 · 100vh · none | Caps how tall an element can grow. |
max-width | 0 · 640px · none | Caps how wide an element can grow. |
min-height | 0 · 100vh | Floors how short an element can shrink. |
min-width | 0 · 640px | Floors how narrow an element can shrink. |
opacity | 0–1 | Transparency of the whole element, including its children — not just its color. |
overflow | visible · hidden · scroll · auto | What happens to content that exceeds its box. |
padding | 0 · 8px · 1rem 2rem | Shorthand for space inside an element's border, around its content. |
padding-top / -right / -bottom / -left | 0 · 8px | Sets one side's padding individually. |
position | static · relative · absolute · fixed · sticky | How an element is positioned relative to its normal flow or an ancestor. |
row-gap | 8px · 1rem | Vertical spacing between flex/grid children. |
text-align | left · center · right · justify | Horizontal alignment of inline content. |
text-decoration | none · underline · line-through | Lines drawn on text — commonly used to remove link underlines. |
text-overflow | clip · ellipsis | How clipped text is indicated — pairs with overflow: hidden; white-space: nowrap;. |
text-transform | none · uppercase · capitalize | Case transformation applied at render time, independent of the source text. |
top / right / bottom / left | 0 · 16px · auto | Offsets used with any position other than static. |
transform | translateX(8px) · scale(1.05) · rotate(3deg) | Moves, scales, or rotates an element without affecting document flow. |
transition | all 0.2s ease | Animates a property change smoothly instead of jumping instantly. |
white-space | normal · nowrap · pre-wrap | How whitespace and line-wrapping inside text is handled. |
width | auto · 100% · 320px | Explicit width of an element's content box. |
z-index | 0 · 10 · 100 | Stacking order for overlapping positioned elements — higher sits on top. |
@keyframes | { from {...} to {...} } | Defines the steps of a named animation for use with animation. |
Length & sizing units
pxAn absolute pixel — doesn't scale with the user's font-size setting. Fine for borders and shadows; avoid for type and spacing that should scale.remRelative to the root (<html>) font-size — the default choice for spacing and type so everything scales together with accessibility zoom.emRelative to the current element's own font-size — compounds inside nested elements, which makes it easy to accidentally double up.%Relative to the parent's corresponding dimension — width % is relative to parent width, margin/padding % is relative to parent width even on the vertical axis.vw / vh1% of the viewport's width / height — useful for full-bleed sections, risky for spacing since it ignores content size entirely.chThe width of the "0" character in the current font — handy for capping a text column to a character-count measure.frA fractional unit valid only inside CSS Grid — divides remaining space proportionally among tracks.clamp(min, preferred, max)Picks a fluid value that never goes belowminor abovemax— one line replacing several breakpoint-specific overrides.
More terms
- CascadeWhen multiple rules target the same element, specificity and source order decide which value wins — not just "last one written."
- SpecificityInline styles beat IDs, IDs beat classes, classes beat element selectors — the tiebreaker before source order matters.
- CSS variable (custom property)Declared as
--name: valueand read withvar(--name)— lets a value like a brand color be defined once and reused everywhere. - Media query
@media (max-width: 768px) { ... }— applies rules conditionally based on viewport or device characteristics. - Pseudo-classA state-based selector like
:hover,:focus, or:nth-child()— targets an element in a particular condition, not a different element. - Pseudo-elementA selector like
::beforeor::afterthat targets a generated sub-part of an element rather than a state. - CombinatorSymbols joining selectors —
A B(descendant),A > B(direct child),A + B(next sibling),A ~ B(any following sibling).
CSS Layout Reference
Flexbox and Grid solve overlapping problems, which is exactly why it's easy to reach for the wrong one. Side by side, with the container/item properties each needs and the patterns each is actually good at.
- Reach for FlexboxOne dimension at a time — a row of nav links, a toolbar, a card's internal header/body/footer stack. Content size drives layout.
- Reach for GridTwo dimensions at once — a page shell, a card grid, a form with aligned labels and inputs across rows. Layout size drives content placement.
- They composeA Grid page shell with Flexbox inside each cell (or vice versa) is the normal shape of a real layout, not a special case.
| Container property | Common values | Use |
|---|---|---|
display: flex | — | Turns an element into a flex container; direct children become flex items. |
flex-direction | row · column · row-reverse | The main axis items lay out along. |
flex-wrap | nowrap · wrap | Whether items wrap to new lines when they run out of room on the main axis. |
justify-content | flex-start · center · space-between · space-around | Alignment along the main axis. |
align-items | stretch · flex-start · center · baseline | Alignment along the cross axis. |
gap | 8px · 1rem | Space between items — no margin hacks needed on the edge items. |
| Item property | Common values | Use |
|---|---|---|
flex-grow | 0 · 1 | How much an item expands into leftover space, relative to its siblings. |
flex-shrink | 0 · 1 | Whether an item is allowed to shrink below its basis when space is tight. |
flex-basis | auto · 200px · 0 | An item's starting size before grow/shrink are applied. |
flex | 1 · 0 1 auto · none | Shorthand for grow, shrink, and basis together — flex: 1 is the common "fill remaining space" rule. |
align-self | auto · center · flex-end | Overrides align-items for one item. |
order | 0 · -1 · 2 | Visual reordering without touching source order — use sparingly, it can break keyboard/tab order. |
| Container property | Common values | Use |
|---|---|---|
display: grid | — | Turns an element into a grid container; direct children become grid items. |
grid-template-columns | repeat(3, 1fr) · 200px 1fr · repeat(auto-fit, minmax(200px, 1fr)) | Defines column tracks — the auto-fit/minmax pattern is a responsive card grid with zero media queries. |
grid-template-rows | auto · repeat(2, 100px) | Defines row tracks. |
grid-template-areas | "header header" "nav main" | Names regions of the grid as ASCII art, then places items by name instead of index. |
gap | 16px · 8px 24px | Space between rows and columns — row value first, then column. |
justify-items / align-items | stretch · center · start · end | Alignment of every item within its own cell, on each axis. |
place-items | center · start end | Shorthand for align-items + justify-items — place-items: center is the one-line centering trick. |
| Item property | Common values | Use |
|---|---|---|
grid-column | span 2 · 1 / 3 · 1 / -1 | Places an item across specific column tracks — 1 / -1 spans the full width. |
grid-row | span 2 · 1 / 3 | Places an item across specific row tracks. |
grid-area | header | Places an item into a named region from grid-template-areas. |
justify-self / align-self | stretch · center · start · end | Overrides item alignment within its own cell. |
- Responsive card grid
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));— cards reflow at any width, no breakpoints written. - Sticky footerOn the page wrapper:
display: flex; flex-direction: column; min-height: 100vh;, thenflex: 1on the main content area. - Full-bleed page shell
grid-template-columns: 1fr min(65ch, 100%) 1fr;centers a readable measure while letting specific children (givengrid-column: 1 / -1) break out full-width. - Holy grail layoutHeader / sidebar / main / aside / footer via
grid-template-areas— the areas syntax makes the shape of the page readable straight from the CSS. - Centering, either toolFlex:
display:flex; align-items:center; justify-content:center;. Grid:display:grid; place-items:center;— Grid's is shorter when centering is the only job.
Media & Container Queries
A media query asks "how big is the viewport." A container query asks "how big is the space this component actually has" — a smaller, more useful question once a component gets reused somewhere its parent didn't expect.
| Syntax | Example | Use |
|---|---|---|
| Min-width (mobile-first) | @media (min-width: 768px) { ... } | Base styles target the smallest screen; rules layer on as the viewport grows. |
| Max-width (desktop-first) | @media (max-width: 767px) { ... } | Base styles target the largest screen; rules override as the viewport shrinks. Pick one direction per project, not both. |
| Range syntax | @media (768px <= width < 1024px) { ... } | Modern shorthand for a min/max pair — reads closer to plain math than the older and-chained form. |
| Feature query | @media (prefers-color-scheme: dark) { ... } | Not just viewport size — also targets user/system preferences. See Dark Mode & Theming. |
@media print { ... } | A distinct media type, not a width breakpoint — styles applied only when the page is printed or exported to PDF. |
A media query only knows about the viewport — a component styled with one behaves differently depending on where in the page it's dropped, because it has no idea how much space its actual parent gave it.
| Syntax | Example | Use |
|---|---|---|
| Declare a container | .card-grid { container-type: inline-size; } | Opts an element in as a query context for its descendants — inline-size tracks width only, the common case. |
| Name it (optional) | container-name: sidebar; | Lets a query target a specific named ancestor when more than one container wraps an element. |
| Query it | @container (min-width: 400px) { .card { ... } } | Styles apply based on the nearest ancestor container's size, not the viewport's. |
| Query units | cqw · cqh · cqi | Container-relative length units — a percentage of the query container's width/height/inline-size, the container equivalent of vw/vh. |
The same card component can now genuinely be "the same component" whether it's alone in a full-width section or squeezed into a three-column sidebar — it reads its own available space and adapts, instead of trusting a viewport width that has nothing to do with it.
- Reach for a media queryWhen the decision genuinely depends on the whole viewport — page-level layout shifts, like switching a sidebar from a fixed column to a collapsible drawer.
- Reach for a container queryWhen the decision depends on a component's own available space — a card that should show more or less detail depending on the column width it's dropped into, regardless of screen size.
- They composeA page shell driven by media queries commonly contains individual components that each carry their own container queries — not a replacement relationship, a layered one.
Checklist
- Breakpoints are chosen from where the content actually breaks, not a fixed device-width list memorized from elsewhere.
- One directional strategy (mobile-first or desktop-first) is used consistently, not mixed within the same stylesheet.
- A component that's reused in more than one layout context uses a container query instead of assuming a fixed viewport.
prefers-reduced-motionandprefers-color-schemeare treated as media features worth querying, not just physical width.
Dark Mode & Theming
Dark mode done well isn't "invert the colors" — flat inverted black crushes contrast and makes shadows read backward. Done as a token-driven theme instead, it's the same technique this site's own dark-mode toggle uses.
| Mechanism | Example | Use |
|---|---|---|
| System preference | @media (prefers-color-scheme: dark) { ... } | Follows the OS/browser setting automatically — the right default when there's no explicit in-app toggle. |
| Manual override | [data-theme="dark"] { ... } | An explicit user choice (a toggle) takes precedence over the system preference and persists independently of it. |
| Persisting the choice | localStorage.setItem('theme', 'dark') | Remembers the manual override across visits — read back on load, before first paint if possible, to avoid a flash of the wrong theme. |
color-scheme | :root { color-scheme: light dark; } | Tells the browser both themes are supported, so native UI (scrollbars, form controls, the browser's own text-selection color) matches without extra CSS. |
This site's own toggle follows exactly this pattern: prefers-color-scheme sets the default, and a data-theme attribute — set by the toggle button, persisted to localStorage — overrides it in either direction.
The token tier from Design Systems is what makes theming tractable: define semantic tokens once (--surface, --ink, --accent), have every component reference the token instead of a raw color, then redeclare the token values under the dark scope. No component needs its own dark-mode logic.
| Token | Light | Dark |
|---|---|---|
--surface | #FAF9F6 | #1A1A1A |
--ink | #201F1D | #ECECEA |
--accent | #2B6E68 | #4A9D95 |
Notice the accent shifts too, not just background/text — a saturated color calibrated for a light background often reads as too intense (or fails contrast) on a dark one, and needs its own dark-mode value rather than a straight carryover.
- ElevationLight mode uses shadow to show "in front"; dark mode reads better with lighter surfaces (not shadow) for elevated layers — a straight color-invert keeps the shadow logic that no longer works.
- Images & iconsPhotos shouldn't invert at all; line icons and diagrams with hardcoded dark strokes need their own dark-mode asset or a
currentColorstroke that follows the token. - Pure black backgroundsTrue
#000against white text produces harsh halation for many readers — a dark gray (#1a1a1a–#121212range) is easier to read for extended periods. - Brand color at full saturationVibrant saturated colors tend to vibrate uncomfortably against a dark background — desaturating slightly for the dark token is a common, deliberate adjustment.
Checklist
- Theme respects
prefers-color-schemeby default, with an explicit override available and persisted. - Every themed value is a token reference, not a raw color duplicated per component.
- Elevation in dark mode uses lighter surfaces, not the light-mode shadow logic carried over unchanged.
- Photographic images are excluded from any invert filter; icons use a token-driven stroke color instead.
- Both themes independently pass WCAG AA contrast — see Color Theory — not just the light theme with dark assumed to inherit it.
Spacing
Spacing is the part of a layout nobody points to directly, but everyone feels — it's what tells the eye which things belong together before a single word is read. Treated as a system instead of a per-screen guess, it's also one of the cheapest ways to make a product feel considered.
The gap between two elements is read as a relationship, whether or not one was intended. A label sitting 4px from its field and 24px from the next field group reads as "this label belongs to this field" — no border or background needed. The same label centered evenly between both reads as ambiguous, and users will hesitate on it even if they can't say why.
A fixed set of values (commonly a 4px or 8px base) covers nearly every real spacing need, from icon-to-label gaps up to section breaks. Picking from this set instead of an arbitrary pixel each time is what makes density read as intentional rather than accidental — and it's what a design system eventually tokenizes as space-xs, space-sm, space-md, and so on.
Padding is space claimed by a component for its own content — it grows or shrinks the component's felt size and stays with it wherever it's placed. Margin is space between components — it's about their relationship to their neighbors, not to themselves. Confusing the two is how spacing scales quietly rot: padding gets nudged to fix a layout problem that was actually a margin problem, and now the component looks wrong everywhere else it's reused.
A minimum ~44×44px touch target (per WCAG and platform guidelines) is a floor, not a full answer — two 44px targets sitting edge-to-edge still produce mis-taps. Adjacent interactive elements need spacing between them, not just size, especially on touch where there's no hover state to warn someone they're about to hit the wrong thing.
When line-height, margins, and section spacing are all multiples of one baseline unit, text blocks stay aligned to an invisible grid as they stack — nothing feels randomly offset from its neighbor. This matters most in long-form content and dense data screens, where dozens of stacked elements make any inconsistency compound and become visible.
Checklist
- Every spacing value traces back to a defined scale — no arbitrary or one-off pixel values.
- Elements that belong together sit visibly closer than elements that don't — proximity alone signals the grouping.
- Padding changes are used to resize a component; margin changes are used to reposition it relative to neighbors — not swapped for each other as a quick fix.
- Adjacent tap targets have spacing between them, not just a minimum size each.
- Stacked text blocks (headings, paragraphs, list items) align to a consistent vertical rhythm.