EmpireUI
Get Pro
← Blog8 min read#brutalism#portfolio#design

Brutalism Portfolio Design: Raw, Bold, Impossible to Ignore

Brutalist portfolios break every "good design" rule on purpose — thick borders, clashing type, zero subtlety. Here's how to build one that lands clients.

Bold brutalist portfolio layout with thick black borders and raw typography

What Brutalism Actually Means (and What It Doesn't)

Brutalism in web design didn't start as a trend someone named at a conference. It borrowed from 1950s architectural brutalism — exposed concrete, no decorative cladding, honesty of materials. On the web, that translates to: raw HTML aesthetics, visible structure, no attempt to hide the grid, and type so large it basically shouts at you.

Here's the thing people get wrong: brutalism isn't about being ugly. It's about being intentional with rawness. There's a difference between a brutalist portfolio that makes you feel something and a site that just forgot to add CSS. The former has deliberate contrast ratios, a reason for every thick border, and typography that was chosen — not just left at the browser default.

In practice, the style started showing up heavily in portfolio work around 2019, but the version you're building in 2026 is more refined. Designers who've spent years with glassmorphism and soft neumorphism are swinging hard in the opposite direction. The reaction is legible: no blur, no frosted glass, no 12px border-radius on everything.

Worth noting: brutalism sits close to neobrutalism but they're not identical. Neobrutalism adds a bit more playfulness — offset drop shadows, bolder color fills. Classic brutalism leans more monochrome, stark, and aggressive with whitespace. Your portfolio can mix both, but you should know which aesthetic decision you're making at any given moment.

Typography Is the Foundation, Not the Afterthought

If brutalism had one load-bearing wall, it'd be type. Not body copy — headings. We're talking 120px at desktop, uppercase, tight letter-spacing, possibly a condensed or extended weight you'd normally never reach for. The font does the heavy lifting that images would do in a more conventional portfolio.

Honestly, the font choice alone can make or break the whole thing. Something like Space Grotesk at 900 weight, stretched to letter-spacing: -0.04em, set at font-size: clamp(64px, 10vw, 144px) — that's brutalism in one CSS declaration. Pair it with a monospace for body text and you've got contrast without even touching color.

Quick aside: loading a massive display font just for headings will tank your LCP if you're not careful. Subset the font to the characters you actually use, or self-host it with font-display: swap. Check out the typography scale guide for the math behind a proper type scale — even brutalist portfolios benefit from a rational size system underneath the chaos.

/* Brutalist heading — no apologies */
.hero-title {
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 900;
  font-size: clamp(56px, 10vw, 140px);
  line-height: 0.95;
  letter-spacing: -0.04em;
  text-transform: uppercase;
  color: #0a0a0a;
}

/* Monospace body for that raw terminal energy */
.body-text {
  font-family: 'JetBrains Mono', monospace;
  font-size: 15px;
  line-height: 1.6;
  max-width: 68ch;
}

One more thing — don't center your hero text. Left-aligned type with a hard left edge reads more brutalist. Centering softens things. You're not going for soft.

The Grid: Visible, Rigid, and Weirdly Beautiful

Conventional design hides the grid. Brutalism exposes it. You want the underlying structure to be visible — either through explicit borders on grid cells, hard-edge background fills that show column divisions, or intentional overflows that make the structure obvious by breaking it.

A 12-column grid still works. But instead of spacing between columns with gutters, you draw a 2px or 3px border between them. That border is your gutter. It's functional and decorative at once, which is very on-brand for brutalism. Below is a minimal setup using CSS Grid with exposed dividers.

.portfolio-grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  /* No gap — we use borders instead */
  gap: 0;
  border: 3px solid #0a0a0a;
}

.grid-cell {
  border-right: 3px solid #0a0a0a;
  border-bottom: 3px solid #0a0a0a;
  padding: 32px;
}

.grid-cell:nth-child(12n) {
  border-right: none;
}

Look, you can absolutely use CSS Grid's gap property and fake the exposed-border aesthetic with background colors. But actually drawing borders on cells gives you more control, especially when cells span different column counts at different breakpoints. The structure shouldn't collapse into something gentle at mobile — shrink it aggressively, maybe go to a 2-column layout, but keep those borders.

Asymmetry is your friend here. Don't make all cells equal height. Let content dictate cell size. A case study card that spans 8 columns next to a 4-column text block looks deliberate. Everything the same size looks like a grid component library example, not a brutalist portfolio.

Color: One Loud Accent or Pure Black and White

Brutalist portfolios typically go one of two routes: pure monochrome (black, white, maybe one gray) or a single electric accent color applied with zero restraint. What they almost never do is use four or five harmonious brand colors, because that's exactly what brutalism is pushing back against.

The electric accent approach hits hard. Pick something like #FF3300 or #FFEE00 — something that triggers a physical response when you see it. Use it on hover states, active navigation, maybe a single marquee strip. The rest of the layout stays black and white. That contrast makes the accent feel violent in the best possible way.

:root {
  --bg: #f5f5f0;
  --ink: #0a0a0a;
  --accent: #ff3300; /* One color. Just one. */
}

a:hover,
.nav-item.active {
  background-color: var(--accent);
  color: var(--bg);
}

.tag {
  border: 2px solid var(--ink);
  background: var(--accent);
  padding: 4px 10px;
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
}

If you want to go monochrome, you still have more range than you'd think. Black text, off-white background (something like #f5f5f0 rather than #ffffff — pure white reads clinical), and dark fill on interactive states. The hover state becomes the only color event on the page. That restraint makes interaction feel meaningful.

You can also pull inspiration from the neobrutalism components to see how offset shadows work with flat fills. Sometimes stealing one technique from a neighboring aesthetic is enough to make your palette feel distinctive rather than just severe.

Project Cards That Don't Look Like Cards

The average portfolio has rounded cards with drop shadows, hover animations, and consistent padding. A brutalist portfolio has none of that — or at least, it subverts every single convention deliberately. Your project entries might just be rows in a table. Or full-bleed image strips with overlaid text at a 90-degree rotation. Or numbered list items in a monospace font.

Honestly, the most effective brutalist project layout I've seen is a simple numbered list. The number is enormous — like 200px tall, acting as a design element — and the project details sit in a narrow column to its right. Zero images above the fold. Just text, a year, a client name, a category tag. The work speaks when you click through, not before.

// Brutalist project list item
function ProjectRow({ number, title, year, category, href }) {
  return (
    <a
      href={href}
      className="project-row"
      style={{
        display: 'grid',
        gridTemplateColumns: '120px 1fr auto',
        alignItems: 'start',
        borderBottom: '2px solid #0a0a0a',
        padding: '24px 0',
        textDecoration: 'none',
        color: 'inherit',
        gap: '32px',
      }}
    >
      <span style={{ fontSize: 64, fontWeight: 900, lineHeight: 1, color: '#ccc' }}>
        {String(number).padStart(2, '0')}
      </span>
      <span style={{ fontSize: 24, fontWeight: 700, textTransform: 'uppercase' }}>
        {title}
      </span>
      <span style={{ fontFamily: 'monospace', fontSize: 13, paddingTop: 6 }}>
        {year} — {category}
      </span>
    </a>
  );
}

That said, if you want images, use them at full bleed — no rounded corners, no box shadow, no 16px margin on all sides. The image bleeds to the border of its cell. It hits a hard edge and stops. That's the point.

For hover states, avoid scale transforms and subtle opacity changes. Instead, flip the background color. Invert the text. Move a thick underline from 0 to full width with width animation. The interaction should feel like hitting a physical button, not gliding over glass. Browse the neobrutalism components to see ready-made examples of this exact interaction pattern.

Motion: Minimal, Mechanical, Deliberate

Animation in a brutalist portfolio should feel like a machine moving, not a fluid transitioning. If something slides in, it slides in on a perfectly linear easing (linear or steps()), not cubic-bezier(0.34, 1.56, 0.64, 1). That spring easing that everyone uses for cards? Gone. Replace it with transition: all 0.1s linear or a CSS step animation.

Page transitions, if you use them, work well as instant cuts — no fade, no slide, just a new state. Or you can do a hard wipe using clip-path. Something like animating clip-path: inset(0 100% 0 0) to clip-path: inset(0 0% 0 0) over 300ms with a linear ease gives you a shutter effect that feels mechanical and intentional.

@keyframes wipe-in {
  from { clip-path: inset(0 100% 0 0); }
  to   { clip-path: inset(0 0% 0 0); }
}

.page-enter {
  animation: wipe-in 0.25s linear forwards;
}

/* Hover state — no spring, just a flip */
.project-row {
  transition: background-color 0.08s linear, color 0.08s linear;
}

.project-row:hover {
  background-color: #0a0a0a;
  color: #f5f5f0;
}

Scrolling animations are fine, but keep them simple. A title that reveals character by character using a steps animation, or a number that counts up — those work. Parallax scrolling and 3D perspective transforms belong in a different aesthetic entirely. If you find yourself reaching for Framer Motion's spring configs, take a step back and ask whether the animation is serving the brutalism or undermining it.

Shipping It: CSS Architecture and Performance

Brutalist doesn't mean slow. The irony is that a brutalist portfolio — with its minimal imagery, flat colors, and no-gradient aesthetic — should be extremely fast. You're not loading a 3MB hero video or a WebGL particle system. But you still need to be deliberate about what you include.

Keep your CSS lean. Since brutalism avoids utilities like rounded corners and shadows in most places, you won't need a full Tailwind config. If you're on Tailwind, a minimal config with just the grid, flexbox, and typography utilities will do. If you're writing vanilla CSS, you can absolutely fit the entire portfolio style in under 8KB of CSS.

For fonts, load one display font (for headings) and one monospace (for body). Two fonts, both subsetted. That's it. Use font-display: optional if you want zero layout shift, or font-display: swap if you're fine with a brief FOUT. The fluid typography guide has solid patterns for responsive type without media queries — clamp() is genuinely useful here and keeps your CSS shorter.

One more thing — test your color contrast. Brutalism's high-contrast aesthetic usually passes WCAG AA easily for large text, but some accent-on-white combinations at small sizes can fail. Run your palette through a checker. Having a brutalist portfolio that's inaccessible is a bad look in 2026, and the Empire UI box shadow generator can help you test visual states without writing CSS by hand.

Deploy on Vercel or Netlify, enable brotli compression, and you're done. A well-built brutalist portfolio should load in under 1.2 seconds on a mid-range mobile connection. That's not hard to hit when you're not fighting your own design system.

FAQ

Is brutalism good for a professional portfolio, or will clients think it's broken?

Depends on who your clients are. Creative directors, tech startups, and independent studios tend to respond well to it — it signals confidence and taste. If you're targeting enterprise HR portals, maybe soften it a bit.

What fonts work best for a brutalist portfolio?

Heavy grotesques at extreme weights: Space Grotesk 900, Bebas Neue, or Monument Extended. Pair with a monospace like JetBrains Mono or IBM Plex Mono for body text. Avoid anything that reads as 'friendly' or 'rounded.'

How is brutalism different from neobrutalism?

Neobrutalism adds offset box shadows and often brighter fills — it's more playful and colorful. Classic brutalism is starker: mostly monochrome, no shadows, harder edges. They share the exposed-grid DNA but diverge in mood.

Can I use a brutalist style with a React component library?

Yes, but you'll spend time overriding defaults. Most component libraries inject border-radius and box-shadow everywhere. You're better off building core components from scratch and borrowing utilities selectively.

Free components in 40 styles
React & Tailwind, copy-paste ready.
Browse →

Read next

Brutalist Portfolio in 2026: Raw HTML Aesthetic, No-BS GridText Gradient Effects in CSS: 8 Techniques Beyond bg-clip-textNeobrutalism in Tailwind CSS: Bold Shadows, Raw Typography, Loud ColorCSS Box Shadow: The Complete Guide With Live Examples