Web Design for Engineers Who Don't Design
Practical web design principles that make sense to engineers. Less aesthetics, more systems thinking about layout, typography, and user interfaces.

The Engineer's Design Problem
Most engineers I've worked with can build complex distributed systems but freeze when asked to design a simple form. The problem isn't ability—it's that design is taught as intuition and taste when it's actually a set of constraints and systems.
I'm not a designer. But I've shipped enough interfaces to know that good web design follows patterns you can learn and apply systematically. Here's what actually matters when you're building for the web.
Layout as a Grid System
Forget pixel-perfect positioning. Modern web design is constraint-based layout using flexbox and grid.
.container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 2rem;
}
This snippet does something simple: create as many columns as fit, each at least 300px wide, with consistent spacing. The browser handles the math. You define the constraints.
Think of layout in terms of:
- Container max-width: 65-75 characters for reading, ~1200px for dashboards
- Spacing scale: use multiples of 4 or 8 (8px, 16px, 24px, 32px...)
- Breakpoints: mobile (<640px), tablet (640-1024px), desktop (>1024px)
Don't position things absolutely unless you're building a canvas tool or game. Let the layout system work.
Typography Is 95% of Design
A well-set page with good typography and no other styling looks professional. A poorly-set page with fancy graphics looks amateur.
Start here:
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
font-size: 16px;
line-height: 1.6;
color: #333;
}
h1 { font-size: 2.5rem; line-height: 1.2; margin-bottom: 1rem; }
h2 { font-size: 2rem; line-height: 1.3; margin-top: 2rem; }
p { margin-bottom: 1rem; max-width: 65ch; }
Key principles:
- Line height: 1.5-1.6 for body text, tighter (1.2-1.3) for headings
- Line length: 45-75 characters per line for readability
- Scale: each heading level should be noticeably different (1.25-1.5x ratio)
- System fonts: they're free, fast, and familiar
If you want to use custom fonts, load them properly:
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preload" as="style" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap">
And limit yourself to 2-3 weights maximum. Every weight is another network request.
Color: Work in HSL, Not Hex
Hex colors are how computers store RGB values. HSL (Hue, Saturation, Lightness) is how humans think about color.
:root {
--primary-hue: 210;
--primary: hsl(var(--primary-hue), 70%, 50%);
--primary-dark: hsl(var(--primary-hue), 70%, 35%);
--primary-light: hsl(var(--primary-hue), 70%, 95%);
}
Now you can derive hover states, backgrounds, and borders by adjusting lightness while keeping hue consistent. This creates visual harmony without a design system.
For text contrast, aim for 4.5:1 ratio minimum (7:1 is better). Use a contrast checker—don't guess.
Whitespace Is a Feature, Not a Bug
Beginners fill every pixel. Experienced designers use emptiness deliberately.
Good spacing creates visual hierarchy:
- Related items: 0.5-1rem apart
- Separate sections: 2-4rem apart
- Major page divisions: 4-8rem apart
section + section {
margin-top: 4rem;
}
.card {
padding: 2rem;
}
.card > * + * {
margin-top: 1rem;
}
That last rule (the "lobotomized owl" selector) adds spacing between any adjacent children. It's a surprisingly effective default.
Interaction States Matter
Every interactive element needs at least three states: default, hover, and active/focus.
.button {
background: var(--primary);
transition: all 0.2s ease;
}
.button:hover {
background: var(--primary-dark);
transform: translateY(-1px);
}
.button:active {
transform: translateY(0);
}
.button:focus-visible {
outline: 3px solid var(--primary);
outline-offset: 2px;
}
The focus state is required for accessibility. Never set outline: none without a visible replacement.
Responsive by Default
Mobile isn't an afterthought—it's often the majority of traffic. Design mobile-first, then enhance.
/* Mobile-first base */
.nav { flex-direction: column; }
/* Desktop enhancement */
@media (min-width: 768px) {
.nav { flex-direction: row; }
}
This is easier than trying to undo desktop styles for mobile. Start constrained, then expand.
Test on real devices, not just browser DevTools. Touch targets need to be at least 44x44px. Hamburger menus are fine.
Tools That Actually Help
Skip Photoshop. Modern web design happens in the browser or in tools like Figma.
What I actually use:
- Browser DevTools: live CSS editing, layout debugging
- Figma: when I need to share mockups with actual designers
- Can I Use: checking browser support before using new features
- WebAIM Contrast Checker: ensuring text is readable
Most of the time, I write HTML and CSS directly. The feedback loop is faster than any design tool.
The Real Secret
Good web design isn't about having taste—it's about having constraints. Pick a spacing scale and stick to it. Choose two fonts maximum. Establish a color palette and derive everything from it. Use a consistent layout grid.
Within tight constraints, most decisions make themselves. You're not paralyzed by infinite options because you've already eliminated 95% of them.
The websites you think look "designed" are usually just consistently applied systems. Build the system, then fill in the content. That's engineering thinking applied to design.
And when you really need something custom? That's when you hire a designer. But for most internal tools, documentation sites, and portfolio pages, these principles will get you 90% of the way there.