Starter template
Starter structure
Start with a predictable structure. Good architecture should remove decisions, not create new ones every Monday morning. The goal is a system people can explain without opening seven files first.
Real-world folder structure
css/
critical.css
settings/
variables.css
media.css
fonts.css
base/
reset.css
typography.css
helpers/
vh.css
a11y-link.css
layout/
site-head.css
components/
logo.css
button.css
main-nav.css
card.css
theme/
brand.css
legacy/
vendor.css
old-site.css
hacks/
temporary-fixes.css
Folder names may vary. Some teams group files under
components/ with subfolders. The important rule is ownership,
not folder worship.
Root CSS file as an import map
Your main stylesheet should define layer order first, then import files into the correct place. It should not become the place where emergency CSS goes to retire.
@layer legacy, settings, base, utilities,
layout, components, theme, hacks;
@import 'legacy/vendor' layer(legacy);
@import 'legacy/old-site' layer(legacy);
@import 'settings/variables' layer(settings);
@import 'settings/media' layer(settings);
@import 'settings/fonts' layer(settings);
@import 'base/reset' layer(base);
@import 'helpers/vh' layer(utilities);
@import 'layout/site-head' layer(layout);
@import 'components/logo' layer(components);
@import 'components/button' layer(components);
@import 'components/main-nav' layer(components);
@import 'components/card' layer(components); Tokens first
Use variables for spacing, typography, colour, shadows, radius, and layout decisions. Random values spread inconsistency fast and turn design into avoidable inconsistency.
:root {
--ff: 'Funnel Sans', system-ui;
--ff-display: 'Funnel Display', system-ui;
--fs: 1rem;
--fs-l: 1.5rem;
--space: 1rem;
--space-m: 1.5rem;
--c-red: hsl(343 100% 45.5%);
--c-blue: hsl(222 53% 35%);
--shadow-m: 0 2px 8px rgba(0, 0, 0, 0.12);
} Change the token, not twenty unrelated selectors hunting for the correct shade of red.
Fonts belong in settings
Font loading belongs in the settings layer. Typography defaults belong in base. Components should not be quietly importing font decisions like suspicious luggage.
@font-face {
font-family: 'Funnel Display';
font-style: normal;
font-display: swap;
font-weight: 300 800;
src: url('/fonts/funnel-display-variable.woff2')
format('woff2-variations');
} Working rules
- One component, one partial.
- No IDs for styling.
- No
!importantunless there is a real emergency. - Base styles stay in the base layer.
- Utilities stay rare and purposeful.
- Theme changes presentation, not structure.
- Legacy CSS stays low in the cascade.
- Hacks are temporary and visible.
- Large files trigger review, not pride.
What to avoid
- One giant site.css containing everything.
- Component styles mixed into reset or base files.
- Random colours and spacing values spread across components.
- Third-party CSS imported without a legacy layer.
- Temporary fixes hidden inside normal component files.
- Utility chains replacing actual component architecture.
If the project becomes difficult to explain, it will become worse to maintain.