Web Platform Design Rules (Sectioned)
Load individual sections as needed. Each section is self-contained.
Accessibility / WCAG [CRITICAL]
Rules
Use semantic HTML elements. Use
<main>,<nav>,<header>,<footer>,<article>,<section>,<aside>,<figure>,<dialog>,<details>for their intended purpose. Never use<div onclick>when<button>exists.Add ARIA labels to interactive elements without visible text. Icon buttons need
aria-label. Groups needaria-labelledby. Do not add ARIA when visible text already provides the name.Ensure keyboard navigation. All interactive elements reachable via Tab. Custom widgets need
tabindex="0"and keydown handlers. Trap focus inside modals. Never usetabindex> 0.Provide visible focus indicators. Use
:focus-visiblewith 3px outline and 2px offset. WCAG 2.2 requires minimum 2px perimeter area with 3:1 contrast.Include skip navigation links. Add
<a href="#main-content" class="skip-link">Skip to main content</a>before the nav. Visually hidden until focused.Write appropriate alt text. Informative images: describe content. Decorative images:
alt="". Functional images: describe the action. Complex images: short alt + linked long description.Meet color contrast ratios. Normal text: 4.5:1. Large text (>=24px or >=18.66px bold): 3:1. UI components and graphics: 3:1. Never rely on color alone.
Associate labels with form inputs. Use
<label for="id">or wrap input in<label>. Never use placeholder as the only label.Identify errors in text and link to inputs. Use
aria-describedbyoraria-errormessagewitharia-invalid="true". Error text must describe how to fix the problem.Use ARIA live regions for dynamic updates.
aria-live="polite"for non-urgent updates.role="alert"for time-sensitive messages.role="status"for status messages.Prefer native HTML over ARIA roles. Use
<button>not<div role="button">. Use<nav>not<div role="navigation">. ARIA is a supplement, not a replacement.
Responsive Design [CRITICAL]
Rules
Build mobile-first. Base styles for smallest viewport. Add complexity with
min-widthmedia queries.Use fluid sizing with
clamp(),min(),max(). Fluid typography:font-size: clamp(1.75rem, 1.2rem + 2vw, 3rem). Fluid containers:width: min(90%, 72rem).Use container queries for component-level responsiveness. Set
container-type: inline-sizeon wrappers. Use@containerfor layout changes based on available space.Set breakpoints at content, not device widths. Break where your layout breaks. Common starting points: 30rem, 48rem, 64rem, 80rem.
Ensure touch targets are 44x44px minimum. Expand small icons with
::afterpseudo-element and negativeinset. Maintain 24px spacing between adjacent targets.Include viewport meta tag.
<meta name="viewport" content="width=device-width, initial-scale=1">. Never usemaximum-scale=1oruser-scalable=no.Prevent horizontal scrolling. Set
max-width: 100%; height: autoon images/video/iframes. Useoverflow-wrap: break-wordfor long text. Wrap tables inoverflow-x: autocontainer.
Forms [HIGH]
Rules
Label every input. Use
<label for="id">with matchingidon the input. Every field needs a visible, programmatically associated label.Set autocomplete attributes. Use
autocomplete="email",autocomplete="tel",autocomplete="name",autocomplete="street-address", etc. Required by WCAG SC 1.3.5.Use correct input types.
type="email"for email,type="tel"for phone,type="url"for URLs,inputmode="numeric"for numeric data without spinners.Validate inline on blur. Show errors after the user leaves a field, not on every keystroke. Use
aria-invalidandaria-describedbyto link errors.Group related fields with fieldset/legend. Radio groups, checkbox groups, and address blocks belong in
<fieldset>with a<legend>.Indicate required fields. Use
requiredattribute. Show a visible marker (asterisk or "(required)" text). If most fields are required, indicate optional fields instead.Keep submit buttons enabled. Validate on submit and show errors. Disabled buttons fail to explain why the user cannot proceed.
Typography [HIGH]
Rules
Use system font stacks or web fonts with fallbacks. System:
font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif. Web fonts: addfont-display: swap.Use relative units.
remfor font sizes and spacing.emfor component-relative sizing. Never setfont-sizeinpxon body text.Set body line height to at least 1.5. Headings can use 1.2. Paragraph spacing at least 2x font size. Required by WCAG SC 1.4.12.
Limit line length to ~75 characters. Use
max-width: 75chormax-width: 40remon prose containers.Use proper typographic details. Curly quotes via CSS
quotesproperty. Tabular numbers (font-variant-numeric: tabular-nums) for data columns.Maintain heading hierarchy.
h1throughh6in order, no skipping. Oneh1per page. Style headings with classes if visual size differs from semantic level.
Performance [HIGH]
Rules
Lazy load below-fold images. Use
loading="lazy". Above-fold hero images getfetchpriority="high".Set explicit image dimensions. Add
widthandheightattributes to prevent Cumulative Layout Shift (CLS).Use resource hints.
<link rel="preconnect">for third-party origins.<link rel="preload">for critical fonts and CSS.<link rel="dns-prefetch">for non-critical origins.Code-split JavaScript. Use dynamic
import()for route-based and interaction-based splitting. Load heavy libraries only when needed.Virtualize long lists. Render only visible rows plus a small buffer for lists exceeding a few hundred items.
Avoid layout thrashing. Batch all DOM reads, then batch all DOM writes. Never interleave reads and writes in a loop.
Use
will-changesparingly. Apply only to elements that will animate. Remove after animation completes. Never apply globally.
Animation and Motion [MEDIUM]
Rules
Respect
prefers-reduced-motion. Wrap all animations in a media query check. Setanimation-duration: 0.01msandtransition-duration: 0.01msfor reduced motion preference.Animate only compositor-friendly properties. Use
transformandopacity. Avoid animatingwidth,height,top,left,margin, orpadding.No flashing content above 3Hz. Content that flashes more than 3 times per second can trigger seizures. WCAG SC 2.3.1.
Use transitions for state changes. Hover, focus, open/close, and visibility changes should transition smoothly (150-300ms).
Motion must be meaningful. Animate to communicate state, guide attention, or show spatial relationships. Never animate purely for decoration.
Dark Mode and Theming [MEDIUM]
Rules
Detect system preference. Use
@media (prefers-color-scheme: dark)to switch theme tokens.Define themes with CSS custom properties. All colors, shadows, and surfaces as
--custom-properties. Toggle entire themes by redefining variables.Set the
color-schememeta tag.<meta name="color-scheme" content="light dark">. Also setcolor-scheme: light darkin CSS for native form controls.Verify contrast in both modes. Dark mode commonly fails contrast on secondary text and disabled states. Re-check all ratios.
Adapt images to theme. Use
<picture>withmedia="(prefers-color-scheme: dark)"for alternate assets. Usefilter: brightness()for simple adjustments.
Navigation and State [MEDIUM]
Rules
URL reflects state. Every meaningful view has a unique URL. Use
URLSearchParamsandhistory.pushStatefor filters, tabs, and pagination.Support browser back/forward. Handle
popstateevents to restore state from the URL.Mark active navigation items. Use
aria-current="page"on the active link. Style with[aria-current="page"]selector.Add breadcrumbs for deep hierarchies. Use
<nav aria-label="Breadcrumb">with an ordered list. Mark current page witharia-current="page".Manage scroll restoration. Set
history.scrollRestoration = 'manual'in SPAs. Save and restore scroll position on navigation.
Touch and Interaction [MEDIUM]
Rules
Use
touch-actionfor scroll control.pan-yfor vertical-only scroll areas.pan-xfor carousels.nonefor canvas/map elements.Disable tap highlight. Set
-webkit-tap-highlight-color: transparenton buttons and links; provide your own active state instead.Pair hover with focus-visible. Every
:hoverstyle must have an equivalent:focus-visiblestyle.No hover-only interactions. Tooltips and dropdowns must work with
:focus-withinand click/tap. Touch devices have no hover state.Use CSS scroll snap for carousels.
scroll-snap-type: x mandatoryon the container.scroll-snap-align: starton each item.
Internationalization [MEDIUM]
Rules
Set
langattribute on<html>. Use BCP 47 language tags (en,fr,ar,zh-Hans). Override withlangon elements containing different-language content.Use
dir="auto"for user-generated content. Let the browser detect text direction. Usedir="rtl"ordir="ltr"when direction is known.Format with Intl APIs.
Intl.DateTimeFormatfor dates.Intl.NumberFormatfor numbers and currency.Intl.RelativeTimeFormatfor relative time.Intl.ListFormatfor lists.Avoid text in images. Text in images cannot be translated, resized, or read by screen readers.
Use CSS logical properties.
margin-inline-startnotmargin-left.padding-block-endnotpadding-bottom.inset-inline-startnotleft.text-align: startnottext-align: left.Support RTL layouts. Test in RTL mode. Flip directional icons with
transform: scaleX(-1)in[dir="rtl"]. Flexbox and Grid handle flow reversal automatically with logical properties.
Quick Reference: Semantic HTML Elements
| Element | Use For | Replaces |
|---|---|---|
<button> |
Actions, toggles | <div onclick>, <a href="#"> |
<a href> |
Navigation to URLs | <span onclick> |
<nav> |
Navigation blocks | <div class="nav"> |
<main> |
Primary content | <div class="main"> |
<header> |
Page/section header | <div class="header"> |
<footer> |
Page/section footer | <div class="footer"> |
<article> |
Independent content | <div class="article"> |
<section> |
Thematic group | <div class="section"> |
<aside> |
Side content | <div class="sidebar"> |
<dialog> |
Modal dialogs | <div class="modal"> |
<details>/<summary> |
Disclosure | Custom accordion JS |
<fieldset>/<legend> |
Form groups | <div class="group"> |
<figure>/<figcaption> |
Figures with captions | <div class="image-wrap"> |
<time> |
Dates and times | <span class="date"> |
<search> |
Search landmark | <div role="search"> |
<output> |
Calculation result | <span class="result"> |
<progress> |
Progress indicator | <div class="progress"> |
<meter> |
Scalar measurement | <div class="gauge"> |
Quick Reference: Common ARIA Patterns
| Pattern | Key Attributes |
|---|---|
| Tabs | role="tablist", role="tab", role="tabpanel", aria-selected, aria-controls |
| Accordion | <button aria-expanded>, aria-controls, <div role="region"> |
| Modal | <dialog> or role="dialog", aria-modal="true", aria-labelledby |
| Combobox | role="combobox", aria-expanded, aria-controls, aria-activedescendant |
| Alert | role="alert" (assertive) or role="status" (polite) |
| Tooltip | role="tooltip", aria-describedby on trigger |
| Menu | role="menu", role="menuitem", aria-haspopup |
| Tree | role="tree", role="treeitem", aria-expanded |
| Breadcrumb | <nav aria-label="Breadcrumb">, aria-current="page" |
| Live region | aria-live="polite" or aria-live="assertive", aria-atomic |