Skip to content

Five Cards and the Copy Problem

Adityo Guni Waluyo

My portfolio had a bare list of projects. I added five capability cards: the CSS grid was solved in twenty minutes. The copy took three rewrites.

TL;DR

The CSS grid for his portfolio's service cards was the easy part, done in 20 minutes with MDN's auto-fill recipe. The hard part was the copy, which took three rewrites to compress into short, blunt descriptions that never truncate. His take: layout is a solved problem, so spend the effort on content, equal heights, and a consistent shadow.

My Projects and Services section was a bare list. Project names, maybe a one-line description each, stacked vertically like a README. Visitors landed on my portfolio, scrolled past the intro, hit that section, and I could almost see the blank stare. There was no way to tell at a glance what I actually offer. The section needed structure, and I kept seeing card layouts on other dev portfolios that looked clean and scannable.

So I committed to adding five capability cards. Simple grid, right? Pick a CSS recipe, write a description for each service, done.

The grid was the easy part

I grabbed the MDN Layout Cookbook Card recipe — repeat(auto-fill, minmax(230px, 1fr)) on a CSS grid container, footer pinned to the bottom with a flex column trick [1]. Took maybe 20 minutes to wire up. Cards auto-fill into however many columns fit, they stretch to equal height, everything looks tidy at every breakpoint. No media queries needed. I was half-congratulating myself.

Then I hit the actual wall: writing the copy.

Five cards means five short descriptions. Each one needs to communicate what the service is and why someone should care, in roughly two to four lines. Not a paragraph. Not a tagline. Something in between that reads natural and doesn't waste a single word. I stared at the first card for way longer than I spent on the entire CSS grid.

The temptation, every single time, was to write a sentence and then clip it with text-overflow: ellipsis. Dave Rupert flagged this exact instinct in his pitfalls breakdown — ellipsis truncation leaves you with three or four visible words, which tells the visitor almost nothing [4]. He argues the best option is to just never truncate. Write less, but write enough that the whole thing shows. That advice sounds obvious until you're the one trying to compress "I build performant, accessible front-end interfaces with a focus on design systems and component architecture" into something that fits a 230px-wide card without looking cramped.

What actually worked

Three things made the cards feel right.

Equal heights matter more than you think. The grid auto-fill trick gives you equal row heights for free, but only if you set each card to display: flex; flex-direction: column and let the content area grow. NN/g's component breakdown explains why: cards are containers for a few short, related pieces of information, like a playing card — a short representation of a conceptual unit [2]. When cards in the same row have mismatched heights, the whole grid looks broken even if nothing is technically wrong. Equal height keeps the "set of related things" feeling intact.

Short copy wins. I rewrote each card description three or four times. The final versions are blunt. "API integration and backend automation." "Performance audits and Core Web Vitals." No adjectives. No promises. Each card says what it does, nothing more. It felt too sparse when I first wrote them, but at card scale, sparse is correct.

Consistent shadows signal clickability. NN/g specifically calls out drop shadow as a signifier that the entire card is clickable [2]. I applied the same subtle box-shadow to all five cards, no hover-state changes, no pointer-cursor tricks. The shadow alone does the job. It's a small detail but it removes ambiguity about whether these are decorative or interactive.

Why I kept going back to this

The whole exercise took longer than it should have, and I don't mean the CSS. Writing short copy is harder than writing long copy. You can't hide behind hedging or context. Every word either earns its spot or it's noise. I rewrote the descriptions while looking at them on my phone, because if they didn't scan in two seconds on a small screen, they weren't good enough. Reminds me of the time I built a React textarea setter that silently ignored state, another case where the small detail costs you more than the big feature.

My firm take: the CSS layout for cards is a solved problem. Don't spend time on it. MDN already did the work [1]. Spend your time on the content, because a perfectly aligned grid with vague or truncated descriptions is just a prettier version of the bare list you started with.

I ended up with five cards, each under 40 words, all visible without truncation, equal height in every row, with a shadow that says "click me." The section finally communicates what I do. It only took me three rewrites to get there.

Sources

Related articles