The Breakpoint That Was Hiding the Real Bug
Introduction
This was my first Frontend Mentor junior challenge, and the first time I used CSS Grid for anything real. I'd already built the mobile layout with Flexbox, a single stacked column, before I sat down to work through the desktop layout. That's where the actual learning happened.
Two Grids Instead of One
My first instinct was to wrap four of the five cards in a .group div, turn that into its own 3-column grid, and place the fifth card (Kira) in a separate outer grid next to it. It didn't work.
When I tried to explain my reasoning, I understood why: Kira needed to visually span two rows next to the other four cards, but she wasn't even inside the same grid as them. I didn't know, until this project, that a single grid item can span multiple rows in one column.
Once I understood that was possible, the whole .group wrapper stopped making sense. It wasn't solving a real problem. It was a workaround for something Grid could already do on its own. The fix was to delete .group entirely and flatten the HTML so all five <article> elements are direct children of one grid container.
grid-template-areas
Instead of placing every card with column and row numbers, I used grid-template-areas, writing the layout as a literal map:
grid-template-areas: "daniel daniel jonathan kira"
"jeanette patrick patrick kira";
This clicked immediately. The CSS looks like the layout. Each article gets one line, grid-area: daniel;, and Grid figures out the rest.
I'd guessed correctly that Kira would stretch to fill both rows, but I wasn't sure the two rows would end up equal in height. They don't, by default. With grid-template-rows: auto auto, each row sizes independently based on its own content - they aren't forced to match.
What does happen automatically: every grid item has align-self: stretch by default, so an item spanning multiple rows fills the combined height of every row and gap it spans, no manual syncing required.
Chasing a Stretch Bug Into a Fake Fix
Once the grid was structurally working, the cards looked stretched and awkward, especially Jonathan's and Jeanette's, which had noticeable empty space below their text.
The cause: align-items: stretch was correctly making shorter cards match the height of taller ones in the same row. That part was expected Grid behavior. But justify-content: center on my article rule was then centering the shorter content vertically inside that taller box, creating dead space above and below instead of a clean top-aligned look.
The fix was justify-content: flex-start on article, so content anchors to the top regardless of how tall the box gets.
Before I found that, I tried something else first: I set min-width on .card, which happened to hide the problem by force-widening the container so text wrapped less. It looked fixed. It wasn't.
min-widthsets a floor, and below that value the grid became wider than the viewport, causing horizontal scrollbars.- Switching to
max-width, the actual correct property, let the grid shrink properly again, which immediately re-exposed the real stretch problem.
At 768px, four columns didn't have enough room for comfortable text, so everything wrapped heavily and rows got tall and uneven. That's when I found the real root cause myself: the grid layout simply didn't have enough room to exist at 768px.
The style guide specified mobile at 375px and desktop at 1440px, nothing about a tablet-specific layout, so I moved my breakpoint up to 80rem (1280px), well clear of the cramped zone, and kept Flexbox stacking everywhere below that. I also retuned the typography specifically for the desktop grid, since a layout at 1280px and up has different space needs than the same content at 375px.
After that, I resized the browser slowly across every width to check it. No scrollbars, no stretch issues.
Positioning the Quotation Mark
I'd hidden the decorative quotation mark image with display: none early on and forgot about it until it got pointed out near the end. Placing it behind Daniel's card content taught me three things I hadn't really understood before:
position: relativeon the parent turns it into the anchor that absolutely positioned children measure their offsets against.position: absoluteon the quotation image takes it out of normal document flow so it can overlap content without pushing anything around.z-indexonly works on positioned elements - an element left at the defaultposition: staticignores it completely, no matter the value.
What surprised me more: positioned elements always paint above static ones regardless of z-index. That comparison only happens between positioned elements. So my fix, adding position: relative and z-index: 1 to the text containers, was really about moving them into the positioned category so z-index could apply at all. The number itself mattered less than getting into the right category to begin with.
DOM order alone might have already put the text on top in my case, so the fix mostly added intentional control rather than correcting an active failure.
What I Almost Missed
Working through structural problems like Grid and positioning, it's easy to lose track of visual details entirely. I nearly missed the quotation mark graphic, the box-shadow on the cards, and a leftover wrapper div around Jonathan's avatar from earlier experimentation.
I'm trying to build a habit around this now: a quick detail scan of the design before styling each section - shadows, radius, spacing, hover states - as its own pass separate from the structural work.
For the box-shadow itself, I landed on:
box-shadow: 3.5rem 3.5rem 5rem -2rem hsl(224, 10%, 45%);
- Offset-x and offset-y shift the shadow horizontally and vertically.
- Blur-radius controls how soft the edge is - zero being a hard silhouette.
- Spread-radius grows or shrinks the shadow shape before blur, and a negative value here pulls it inward instead of framing the element evenly.
Small thing, but tuning it by feel taught me more about how the property actually works than reading the syntax did.
What I Take Away From This
The real lesson wasn't Grid syntax. It was learning to trace a visual symptom back to its actual structural cause instead of patching it with another override. The min-width detour looked like a fix. It wasn't one - it just moved the problem somewhere I couldn't see it yet.
A working fix and a correct fix aren't the same thing if the first one is just hiding what's actually wrong underneath.
Comments
No comments yet. Start the discussion.