Convention: Frontend CSS

convention-frontend-css Convention

active convention

Rule

All frontend CSS follows the playground philosophy: real CSS, not utility classes. Mobile-first. Human-verified.

Canonical Reference

The CSS fundamentals guide lives in the playground repo: ~/pal-e-playground/guide/index.html (live at the playground Tailscale funnel). That guide defines the 3 layout systems (Box Model, Flexbox, Grid), the 5 core properties, the 10 rules, and the debugging playbook. Agents must read it before writing frontend CSS.

Design Tokens

All colors, spacing, and typography are defined as CSS custom properties in app.css. Components reference variables (var(--color-bg)), never hardcoded hex values.

Palette

Token Value Purpose
<code>--color-bg</code> #fafafa Page background (light)
<code>--color-text</code> #1a1a1a Primary text
<code>--color-link</code> #0366d6 Links (blue, not pink)
<code>--color-nav-bg</code> #1a1a1a Nav bar (dark)
<code>--color-border</code> #e0e0e0 Subtle borders
<code>--color-tag-bg</code> #e8e8e8 Tag backgrounds

Typography

  • Font: Atkinson Hyperlegible (Google Fonts). Fallback: system sans-serif.
  • Line height: 1.6 minimum for body text
  • Content width: max-width: 48rem, centered with margin: 0 auto

The 3 Layout Systems

System Job When to Use
<strong>Box Model</strong> Sizing &amp; spacing Every element — <code>box-sizing</code>, <code>padding</code>, <code>margin</code>, <code>border</code>
<strong>Flexbox</strong> 1D layout (row OR column) Navbars, button rows, card rows, toolbars, side-by-side panels
<strong>Grid</strong> 2D layout (rows AND columns) Full page layouts, dashboards, image galleries
Decision tree: Need rows AND columns? Grid. Need a row OR column? Flexbox. Need sizing or spacing? Box Model.

The 5 Core Properties

Property Controls Key Values
<code>display</code> What layout system <code>block</code>, <code>flex</code>, <code>grid</code>, <code>inline</code>, <code>none</code>
<code>position</code> Flow vs anchored <code>static</code>, <code>relative</code>, <code>absolute</code>, <code>fixed</code>, <code>sticky</code>
<code>width/height</code> Size constraints Prefer <code>max-width</code> over fixed <code>width</code> for responsive
<code>margin/padding</code> Spacing Margin = outside, padding = inside. Use <code>gap</code> in flex/grid instead of margin hacks
<code>overflow</code> Clipping/scrolling <code>visible</code>, <code>hidden</code>, <code>auto</code>, <code>scroll</code>

Layout Rules

  • *, *::before, *::after { box-sizing: border-box; } — always
  • body { margin: 0; } — always
  • Flexbox for rows/columns, Grid for page layout
  • gap for spacing, not margin hacks
  • max-width + margin: 0 auto for readable content
  • Mobile breakpoint at 600px
  • img { max-width: 100%; } — images scale to container
  • min-height: 100vh for full-page sections

Debugging Playbook

When a layout breaks, run this checklist in order. Most issues resolve before step 5.
  • Inspect the element — Right-click → Inspect. Hover to see the box model (content/padding/border/margin) live.
  • Check the parent's display — Layout bugs almost always come from the parent, not the child. Is the parent flex, grid, or block? Check flex-direction, justify-content, align-items, gap.
  • Check size constraints — Look for width, max-width, height, min-height. Gotcha: height: 100% only works if the parent has a defined height.
  • Check position — Is position: absolute removing the element from flow? Is a relative ancestor missing?
  • Check overflow — Content disappearing? Look for overflow: hidden. Panels need overflow: auto.
  • Toggle styles live — DevTools lets you turn properties on/off and edit values live. Do this constantly.
Quick debug trick: * { outline: 1px solid red; } — makes every box visible. Use DevTools "Computed" tab for final authority on actual applied values.
Common gotchas:
  • "Won't center" — parent isn't flex/grid, or missing justify-content/align-items
  • "Overflowing" — fixed width + padding with content-box, or flex child not shrinking (fix: min-width: 0)
  • "Unexpected space" — default browser margins on headings/paragraphs, or margin collapse

What NOT to Do

  • No hardcoded hex in components — use CSS custom properties
  • No Tailwind arbitrary values (bg-[#0e0e18]) — use real CSS or token-based Tailwind classes
  • No AI slop palette: no cyan-on-dark, no pink neon accents, no gradient text
  • No skipping mobile check — if it scrolls horizontally on phone, it's broken
  • No shipping without Lucas seeing it on device
  • No float, clearfix, table layouts, or manual margin spacing — use flex/grid/gap

Process

  • Design in pal-e-playground with vanilla HTML+CSS (see sop-frontend-experiment)
  • Verify on phone via Tailscale funnel
  • The HTML/CSS IS the spec — no screenshots as intermediary
  • Agent ports CSS to SvelteKit production repo (copy-paste, not rewrite)
  • Lucas verifies production on phone before merge
  • project-frontend-playground — where design happens
  • sop-frontend-experiment — how to create experiments and onboard new projects
  • feedback_frontend_iteration — the lesson that created this convention
  • feedback_svelte_is_html — .svelte files ARE HTML
  • Playground guide: pal-e-playground/guide/index.html