15 — About Section

🖼️ Chapter 15 — About Section

The About section is a classic image + text layout — on desktop the two sit side by side, on mobile they stack. It's also where two of the trickiest positioning concepts in the whole project come together: a floating badge that only works because of a position: relative / position: absolute containing-block relationship, and a checklist built entirely from a single ::before pseudo-element.

What we're building

Here's the HTML we're targeting (already written in Chapter 12):

🏷 HTML — about section structure
<section class="about" id="about"> <div class="container about-inner"> <!-- LEFT: image block --> <div class="about-image-wrap reveal"> <div class="about-img">🎨</div> <div class="about-badge"> <span class="badge-num">8+</span> Years of craft </div> </div> <!-- RIGHT: text block --> <div class="about-text reveal"> <p class="section-label">Our story</p> <h2 class="section-title">Crafted with intention</h2> <p>We've spent eight years turning complex briefs...</p> <ul class="about-checklist">...</ul> <a class="btn btn-primary">Meet the team</a> </div> </div> </section>

Two direct children inside .about-inner: the image wrap (left) and the text block (right). Grid will place them automatically.

9
About Section — two-column grid skeleton

The CSS — outer section

First we style the .about section itself — background colour and generous vertical padding. We use clamp() so spacing breathes on all screen sizes:

🎨 style.css — .about outer section
/* ── Step 9 · About ──────────────────────────────── */ .about { padding: clamp(4rem, 10vw, 7rem) 0; background: var(--clr-bg); /* white — contrasts with the dark stats bar above */ }
Why white here? The Stats bar above uses --clr-dark (#0d1117). A white About section creates a strong contrast break that signals a new page "chapter" to the reader.

The CSS — two-column grid

.about-inner gets a two-column grid. Both columns are equal width (1fr 1fr) and vertically centered with align-items: center so the text doesn't float to the top when the image is taller.

🎨 style.css — .about-inner grid
.about-inner { display: grid; grid-template-columns: 1fr 1fr; /* image | text, equal halves */ gap: clamp(2.5rem, 6vw, 5rem); align-items: center; } /* Mobile: stack columns */ @media (max-width: 899px) { .about-inner { grid-template-columns: 1fr; /* image above, text below */ } }

The gap uses clamp() — wider on large screens where the columns have more room to breathe, narrower on tablet.

Why align-items: center?

Without it, grid children stretch to the tallest cell height by default. If the text column is taller than the image, the image would pin to the top — misaligned. center keeps both columns vertically centered regardless of which side is taller.

Tip — gap vs margin: Using gap on the grid container is cleaner than adding margin-right to one column. Gap disappears automatically when the grid collapses to a single column — no media query needed to clear the gap.

Live demo — grid structure

Toggle the grid outlines on to see exactly how the two columns sit. Toggle "Mobile" to watch the single-column stack.

🎨

Our story

Crafted with intention

We've spent eight years turning complex briefs into clear, purposeful design — for brands that mean business.

Meet the team
Next: We'll style the .about-image-wrap and .about-img elements. The image wrap becomes position: relative — the foundation the absolute-positioned badge will attach to next.

The key concept: position: relative as a containing block

The most important line in this step is one you won't see change anything visually — yet. Setting position: relative on the image wrap creates a containing block for the badge that's coming next.

When you set position: absolute on a child element, the browser walks up the DOM tree looking for the nearest ancestor that has a position other than static. That ancestor becomes the child's reference frame for top, right, bottom, and left. If there's no positioned ancestor, the badge anchors to the viewport — almost certainly not what we want.

.about-image-wrap — position: relative ← containing block
.about-badge — position: absolute
8+ Years of craft

Next, we'll set bottom: -1rem; right: -1rem on this badge — those values will be relative to the image wrap, not the page.

The CSS

🎨 style.css — .about-image-wrap
/* ── Step 9 · About image wrap ───────────────────── */ .about-image-wrap { position: relative; /* containing block for the badge */ border-radius: var(--radius); }

No overflow: hidden here — we need the badge to be able to peek outside the wrap boundary.

🎨 style.css — .about-img
.about-img { aspect-ratio: 4 / 3; /* locks the proportions */ border-radius: var(--radius); background: var(--clr-bg-alt); /* light grey when no real photo */ overflow: hidden; /* clips a real <img> to the border-radius */ display: flex; align-items: center; justify-content: center; font-size: clamp(3rem, 8vw, 5rem); /* scales the emoji placeholder */ transition: transform 0.4s ease; /* subtle zoom on hover */ } .about-img:hover { transform: scale(1.03); /* gentle zoom — image stays clipped */ }

overflow: hidden on .about-img (not the wrap) clips the zoom effect and any real photo to the rounded corners.

Why aspect-ratio: 4 / 3?

Without a fixed height or aspect ratio, a grid cell with no content height would collapse. aspect-ratio tells the browser: "make the height 75% of the width, always." This works for both the emoji placeholder and a real <img> tag — you swap the background for an image later without touching the layout.

✗ Without aspect-ratio
.about-img { background: #f0f0f0; /* no height set → collapses to 0 */ }
✓ With aspect-ratio
.about-img { aspect-ratio: 4 / 3; background: #f0f0f0; /* height derived from width ✓ */ }
Real photo swap: In production you'd replace the emoji div with <img src="team.jpg" alt="..."> and add object-fit: cover; width: 100%; height: 100%; to the img. The aspect-ratio and overflow: hidden on the parent handle the rest.

Live demo — image wrap

Hover the image to see the scale transition. Toggle the annotation to label the key CSS properties.

🎨

Crafted with intention

Eight years turning complex briefs into clear, purposeful design — for brands that mean business.

Meet the team

What overflow: hidden does — and where to put it

This is a subtle but important detail that trips up beginners:

  • .about-img gets overflow: hidden — this clips the zoom effect and a real photo to the rounded corners of the image itself.
  • .about-image-wrap does NOT get overflow: hidden — if it did, the badge we're adding next (which will peek outside the wrap boundary) would be clipped and invisible.
Common mistake: Adding overflow: hidden to the wrap to "fix" the border-radius — then wondering why the absolutely-positioned badge disappears. Clip on the image, not the container.

Part 1 — The floating badge

The badge is a small dark card that hovers at the bottom-right corner of the image, partially overlapping it. It uses position: absolute anchored to the position: relative wrap we set above.

How the coordinates work

With bottom: -1.1rem and right: -1.1rem, the badge starts below and to the right of the wrap's boundary — the negative values pull it outside the box. This creates the overlapping "sticker" effect.

.about-image-wrap (position: relative)
8+ Years of craft
↑ bottom: -1.1rem ← right: -1.1rem
🎨 style.css — .about-badge
/* ── About badge — anchored to image wrap ─────── */ .about-badge { position: absolute; bottom: -1.1rem; /* pull below the image wrap */ right: -1.1rem; /* pull right of the image wrap */ background: var(--clr-dark); /* #0d1117 — dark card */ color: var(--clr-bg); border-radius: var(--radius); padding: 0.75rem 1.1rem; display: flex; align-items: center; gap: 0.5rem; font-weight: 600; font-size: 0.9rem; white-space: nowrap; /* never wrap to two lines */ box-shadow: 0 8px 28px rgba(0,0,0,0.2); transition: transform 0.3s ease, box-shadow 0.3s ease; } .about-badge:hover { transform: translateY(-3px); box-shadow: 0 14px 36px rgba(0,0,0,0.28); } .badge-num { font-size: 1.5rem; font-weight: 800; color: var(--clr-accent); /* accent blue for the number */ line-height: 1; }
Remember: the badge only anchors to the image wrap because .about-image-wrap has position: relative. Without that, the badge would anchor to the nearest positioned ancestor further up the tree — likely the whole page — and appear in the wrong place entirely.

Part 2 — The checklist with ::before

The checklist uses list-style: none to remove the default bullet, then adds a custom circular checkmark via the ::before pseudo-element on each li.

🎨 style.css — .about-checklist
.about-checklist { list-style: none; /* remove default bullet */ padding: 0; margin: 1rem 0; display: flex; flex-direction: column; gap: 0.6rem; } .about-checklist li { display: flex; align-items: center; gap: 0.75rem; font-size: 0.95rem; color: var(--clr-text); } .about-checklist li::before { content: '✓'; /* the checkmark character */ display: inline-flex; align-items: center; justify-content: center; width: 20px; height: 20px; border-radius: 50%; background: rgba(79,142,247,0.12); /* tinted blue circle */ color: var(--clr-accent); font-size: 0.72rem; font-weight: 900; flex-shrink: 0; /* never squish the circle */ transition: background 0.2s, color 0.2s, transform 0.2s; } .about-checklist li:hover::before { background: var(--clr-accent); /* solid on hover */ color: #fff; transform: scale(1.15); }

flex-shrink: 0 on the ::before stops the circle collapsing if the text beside it is long.

Why display: inline-flex on a pseudo-element? ::before is inline by default, so width and height have no effect. Switching it to inline-flex (or flex) makes it a proper box you can size and centre content inside.

Live demo — complete About section

The full section with grid, image, badge, text, and checklist all together. Hover the badge and checklist items to see transitions.

🎨
8+ Years of craft

Crafted with intention

Eight years turning complex briefs into clear, purposeful design — for brands that mean business.

  • Strategy-first approach to every project
  • Pixel-perfect execution, on time
  • Transparent process, zero surprises
Meet the team

Step 9 — complete

  • Grid skeleton — 2-col, centered, fluid gap, mobile stack ✓
  • Image wrapposition: relative, aspect ratio, hover zoom ✓
  • Badgeposition: absolute with negative offsets, hover lift ✓
  • Checklist::before circle checkmarks, hover fill ✓
Next — Chapter 16: Moving on to the Testimonials section — an auto-fit grid of cards, each with a star rating, blockquote, and avatar.