Web Design Methodology
Universal patterns for building production-grade HTML/CSS. This skill covers implementation methodology โ pair with web-design-patterns for specific component designs.
What You Produce
Production-ready HTML/CSS prototypes with:
- Semantic CSS custom properties (tokens)
- BEM-named components
- Mobile-first responsive design
- Accessible markup
- Optional three-state dark mode
File Structure
prototype/
โโโ index.html
โโโ about.html
โโโ services.html
โโโ contact.html
โโโ favicon.svg
โโโ css/
โ โโโ variables.css # Tokens: colours, typography, spacing
โ โโโ styles.css # All component styles (BEM)
โ โโโ mobile-nav.css # Mobile menu styles
โโโ js/
โ โโโ theme.js # Dark mode toggle (only if requested)
โ โโโ mobile-menu.js # Hamburger menu
โโโ media/
โโโ images/
Build order:
variables.css โ tokens first
favicon.svg โ simple SVG from brand colour
styles.css โ all BEM components
mobile-nav.css โ responsive navigation
- JS files โ from
assets/ templates
index.html โ homepage first
- Inner pages โ about, services, contact
- Mobile check โ verify at 375px
BEM Naming
Use Block-Element-Modifier naming. No exceptions.
.hero { }
.card { }
.nav { }
.hero__title { }
.hero__subtitle { }
.hero__cta { }
.card__image { }
.card__content { }
.hero--split { }
.hero--minimal { }
.card--featured { }
.btn--primary { }
.btn--lg { }
Rules:
- Blocks are standalone components
- Elements are children, connected with
__
- Modifiers are variations, connected with
--
- Never nest more than one level:
.hero__content__title is wrong
- Never use element without its block:
.card__image only inside .card
CSS Custom Properties
Use semantic tokens. Never hardcode colours, spacing, or typography values.
See references/css-variables-template.md for the complete token template.
.card {
background: var(--card);
color: var(--card-foreground);
border: 1px solid var(--border);
border-radius: var(--radius);
box-shadow: var(--shadow-sm);
padding: var(--space-6);
}
.card {
background: #ffffff;
color: #333333;
border: 1px solid #e5e5e5;
border-radius: 8px;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
padding: 24px;
}
Dark Mode (Optional)
Dark mode is optional โ only add if the brief requests it. Most business sites ship faster as light-only.
When to include:
- Brief explicitly requests it
- Tech/developer audiences (expected)
- Portfolio/creative sites (aesthetic choice)
When to skip:
- Trades, hospitality, professional services
- When simplicity and fast shipping matter more
If Adding Dark Mode
Use class-based toggle, never CSS media queries.
:root {
--background: #F9FAFB;
--foreground: #0F172A;
--card: #FFFFFF;
--card-foreground: #1E293B;
}
.dark {
--background: #0F172A;
--foreground: #F1F5F9;
--card: #1E293B;
--card-foreground: #F1F5F9;
}
Rules:
.dark class on <html>, toggled via JavaScript
- NEVER use
@media (prefers-color-scheme: dark) โ JS handles system preference
- Every background token needs a paired foreground token
- Brand colours get lighter/more saturated in dark mode
- Backgrounds:
#0F172A to #1E293B range (not pure black)
- Every text-on-background combo must pass WCAG AA (4.5:1)
Use assets/theme-toggle.js for the three-state toggle implementation.
Responsive Design
Mobile-first. Design for 375px, enhance upward.
Breakpoints
@media (min-width: 640px) { }
@media (min-width: 768px) { }
@media (min-width: 1024px) { }
@media (min-width: 1440px) { }
Mobile Priorities
- Phone number visible and tappable without scrolling
- Primary CTA visible without scrolling
- Navigation works via hamburger menu
- Touch targets minimum 44x44px
- No horizontal scrolling ever
- Images scale properly (no overflow)
Wide Screen Constraints
.prose { max-width: 65ch; }
.hero__content { max-width: min(640px, 45vw); }
.container {
max-width: 1280px;
margin-inline: auto;
padding-inline: var(--space-4);
}
.section { padding: clamp(3rem, 6vw, 6rem) 0; }
Use assets/mobile-nav.js for the hamburger menu implementation.
Typography Rules
- Dramatic size contrast. Headlines 3-4x body size.
clamp(2.5rem, 6vw, 5rem) for hero titles.
- Weight variety. Mix 300 and 800 weights. Uniform weight is boring.
- One display moment per page. One oversized word, one dramatic headline, one pull quote. Not three.
- Left-align body text. Centre only for heroes and short statements. Never centre paragraphs.
- Letter spacing on uppercase. Add
letter-spacing: 0.05em minimum.
Colour Usage
The 80/20 rule:
- 80% neutral tones (backgrounds, text, cards)
- 15% secondary/muted brand tones
- 5% primary brand colour (CTAs, one accent per viewport)
If primary is on every heading, border, icon โ nothing stands out.
Spacing System
Not uniform padding. Sections breathe differently:
.section--compact { padding: clamp(2rem, 4vw, 4rem) 0; }
.section { padding: clamp(3rem, 6vw, 6rem) 0; }
.section--spacious { padding: clamp(4rem, 8vw, 10rem) 0; }
Shadow System
| Element |
Shadow |
| Cards at rest |
--shadow-sm |
| Cards on hover |
--shadow-md |
| Dropdowns |
--shadow-lg |
| Modals |
--shadow-xl |
Not everything needs shadow. Use sparingly.
Icons
Use Lucide icons via inline SVG:
- Size: 24px inline, 32-48px for feature blocks
- Stroke width: 1.5 or 2 (consistent throughout)
- Colour:
currentColor (inherits text colour)
- Each icon should communicate something specific
Accessibility
Non-negotiable:
- Semantic HTML:
<header>, <nav>, <main>, <section>