16 — Testimonials

💬 Chapter 16 — Testimonials

The testimonials section reuses the auto-fit grid pattern from Chapter 14's services grid, then goes further — a decorative ::before quote mark, a colour-coded avatar per card, and the margin-top: auto trick that keeps every card's author row pinned to the same baseline, no matter how long each quote is.

10
Testimonials — auto-fit grid, card details

HTML structure

Three testimonial cards sit inside a responsive grid. The section also has a centred header — label, heading, and subheading — before the grid.

🏷 HTML — testimonials section
<section class="testimonials"> <div class="container"> <!-- Centred header --> <div class="testi-header reveal"> <p class="section-label">Kind words</p> <h2 class="section-title">Clients who became partners</h2> <p class="section-sub">Don't take our word for it.</p> </div> <!-- Card grid --> <div class="testi-grid"> <div class="t-card reveal"> <div class="t-stars">★★★★★</div> <blockquote>Lumen took our scrappy idea...</blockquote> <div class="t-author"> <div class="t-avatar">SM</div> <div class="t-author-info"> <strong>Sara M.</strong> <span>Founder, Bloom</span> </div> </div> </div> <!-- × 2 more .t-card --> </div> </div> </section>

Each .t-card has four children: stars, blockquote, and author (avatar + info).

CSS — section and header

🎨 style.css — .testimonials + .testi-header
/* ── Step 10 · Testimonials ──────────────────────── */ .testimonials { padding: clamp(4rem, 10vw, 7rem) 0; background: var(--clr-bg-alt); /* soft grey — contrast from white About */ } .testi-header { text-align: center; max-width: 600px; margin: 0 auto clamp(2.5rem, 6vw, 4rem); }

max-width + margin: 0 auto keeps the header from stretching too wide on large screens — the same centred-container pattern from Chapter 11.

CSS — the auto-fit grid

This is the same auto-fit + minmax pattern used for the Services grid in Chapter 14 — it creates a responsive layout with no media queries at all.

🎨 style.css — .testi-grid
.testi-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 1.5rem; }

With 3 cards and a 280 px minimum: three columns on wide screens, two on tablet, one on mobile — all automatic.

How auto-fit + minmax works — visualised

Grid behaviour at different container widths

Wide (≥ 900 px)

Card 1
Card 2
Card 3

Tablet (≥ 580 px)

Card 1
Card 2
Card 3

Mobile (< 580 px)

Card 1
Card 2
Card 3
auto-fit (what we use)
auto-fit /* Collapses empty tracks — cards stretch to fill the full row width */
auto-fill (alternative)
auto-fill /* Keeps empty tracks — cards don't stretch, leaving gaps on the right */
Rule of thumb: use auto-fit when you want cards to grow and fill the row. Use auto-fill when you want items to stay at their minimum size and leave trailing space — useful for horizontally scrolling carousels.

CSS — base card styles

🎨 style.css — .t-card
.t-card { background: var(--clr-bg); /* white card on grey section */ border-radius: var(--radius); padding: clamp(1.5rem, 3vw, 2rem); border: 1px solid var(--clr-border); box-shadow: 0 2px 12px rgba(0,0,0,0.06); display: flex; flex-direction: column; gap: 1rem; transition: transform 0.3s ease, box-shadow 0.3s ease; } .t-card:hover { transform: translateY(-5px); box-shadow: 0 14px 36px rgba(0,0,0,0.11); }

display: flex; flex-direction: column stacks the four child elements (stars → quote → author) vertically with consistent spacing via gap.

Why a border AND a box-shadow? The subtle 1 px border defines the card edge cleanly on white backgrounds where a shadow alone can look blurry. The shadow adds depth. Together they give a polished, lifted look.

Live demo — grid + card base

Cards have placeholder blocks where the quote, stars, and avatar will go before we style the fine details below. Hover a card to see the lift. Toggle the card outline to inspect the flex column layout.

Clients who became partners

Don't take our word for it.

Card anatomy

Each .t-card has four styled children. The flex-direction: column + gap from the base card spaces them automatically — we just need to style each piece.

.t-stars Five star characters coloured amber — simple, no SVG needed.
blockquote + ::before The quote text sits below a large decorative " generated by ::before, positioned absolutely at the top-left of the blockquote.
.t-author Flex row holding the avatar and info. margin-top: auto pins it to the bottom of the card so all cards align their author rows — even when quote lengths differ.
.t-avatar A coloured circle with initials — no image required. Each card gets a different accent colour via :nth-child.

CSS — stars

🎨 style.css — .t-stars
.t-stars { color: #fbbf24; /* amber — familiar rating colour */ font-size: 1rem; letter-spacing: 2px; /* breathe the stars apart */ line-height: 1; }

CSS — blockquote + decorative opening quote

The large " is injected by ::before and positioned absolutely at the top-left of the blockquote. This is the same pattern from Chapter 15's badge — a position: relative parent and a position: absolute child.

🎨 style.css — blockquote + ::before
.t-card blockquote { margin: 0; padding: 0.75rem 0 0; /* top gap — room for the quote mark */ position: relative; /* containing block for ::before */ font-size: 0.95rem; color: var(--clr-muted); line-height: 1.7; font-style: normal; /* browsers italicise blockquote by default */ } .t-card blockquote::before { content: '\201C'; /* Unicode left double quotation mark " */ position: absolute; top: -0.6rem; left: -0.2rem; font-size: 4rem; line-height: 1; font-family: Georgia, serif; /* serif gives a classic quote character */ color: var(--clr-accent); opacity: 0.15; /* subtle watermark — not in the way */ pointer-events: none; }

pointer-events: none on the pseudo-element means it never intercepts mouse events — the text behind it stays selectable.

Unicode escape \201C: In CSS content, Unicode characters are written as a backslash followed by the hex code point — no u or braces. \201C = " (left double quote), \201D = " (right). Alternatively you can write the character directly: content: '"'.

CSS — author row + avatar

🎨 style.css — .t-author + .t-avatar
.t-author { display: flex; align-items: center; gap: 0.75rem; margin-top: auto; /* push to bottom of flex column — equal-height alignment */ padding-top: 0.75rem; border-top: 1px solid var(--clr-border); } .t-avatar { width: 40px; height: 40px; border-radius: 50%; background: var(--clr-accent); color: #fff; display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 0.8rem; flex-shrink: 0; letter-spacing: 0.03em; } /* Different accent colour per card */ .testi-grid .t-card:nth-child(2) .t-avatar { background: #7c5cbf; } .testi-grid .t-card:nth-child(3) .t-avatar { background: #0d9488; } .t-author-info { display: flex; flex-direction: column; gap: 2px; } .t-author-info strong { font-size: 0.88rem; color: var(--clr-text); } .t-author-info span { font-size: 0.78rem; color: var(--clr-muted); }
margin-top: auto — the equal-height trick. In a flex column, margin-top: auto on the last child absorbs all remaining space, pinning that element to the bottom. When your three cards have quotes of different lengths, the author row stays level across all of them — no JavaScript height-matching needed.

Live demo — complete testimonial cards

Hover cards for the lift. Toggle the annotations to highlight the ::before quote mark and avatar circles.

★★★★★
Lumen took our scrappy idea and turned it into a brand we're genuinely proud to show the world.
SM
Sara M. Founder, Bloom
★★★★★
Working with Lumen felt less like hiring an agency and more like gaining a creative partner who genuinely cared.
JK
James K. CTO, Forma Labs
★★★★★
On time, on budget, and genuinely beautiful. I've worked with a lot of studios — Lumen is in a different league.
AO
Aisha O. Head of Brand, Velo

Step 10 — complete

  • Grid + card baseauto-fit, hover lift, flex column ✓
  • Stars — amber, letter-spaced ✓
  • Blockquoteposition: relative + ::before watermark quote mark ✓
  • Author rowmargin-top: auto equal-height pin, divider border ✓
  • Avatar — initials circle, per-card colour via :nth-child
Next — Chapter 17: The CTA section — a dark gradient band with decorative ::before/::after circles — followed by the four-column footer.