Backgrounds, borders, and shadows: styling real product cards
Part 4 covered the box model's structural layers. This part covers the real visual properties applied on top of those layers — the ones that turn a plain, bordered box into Bright Leaf Coffee's actual, styled product card.
Background colors, images, and real gradients
.hero {
background-color: var(--color-bg);
}
.hero {
background-image: url("/images/hero-coffee-pour.jpg");
background-size: cover;
background-position: center;
}
.badge {
background-image: linear-gradient(135deg, #ff8a3d, #ffb877);
}background-size: cover scales a real background image to fill its element completely, cropping whatever overflows — the real, practical default for a hero image, versus contain, which fits the entire image within the element without cropping, leaving real empty space if the aspect ratios don't match. A linear-gradient() generates a real, genuine color transition entirely in CSS, with zero image file needed at all — a real, meaningful performance advantage over a gradient baked into a JPEG or PNG.
border-radius: real, precise corner rounding
.product-card {
border-radius: 8px;
}
.avatar {
border-radius: 50%;
}
.speech-bubble {
border-radius: 8px 8px 8px 0;
}A single value rounds all four corners uniformly — the real, common case for Bright Leaf Coffee's product cards. 50% on a real square element produces a perfect circle, the standard way to render a genuinely circular avatar or icon. Four separate values (clockwise from top-left) round each corner independently — useful for something like a real speech-bubble shape with one deliberately sharp corner.
box-shadow: real depth, without an image
.product-card {
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}
.product-card:hover {
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
}0 → horizontal offset
2px → vertical offset
8px → blur radius
rgba(...) → the shadow's real color, including transparencyA subtle, real shadow like this is what gives a flat card genuine visual depth, suggesting it's slightly raised off the page — a common, real pattern for making interactive elements like product cards feel tangibly clickable, especially combined with a slightly stronger shadow on :hover (covered fully in part 17) to reinforce that real interactivity.
border vs. outline: a real, easy-to-miss distinction
.product-card {
border: 1px solid var(--color-line);
}
.product-card:focus-visible {
outline: 2px solid var(--color-accent);
outline-offset: 2px;
}border is a real part of the box model — it takes up space and affects layout (recall part 4's box-sizing discussion). outline draws around an element without affecting layout at all, which is exactly why it's the correct real choice for a focus indicator (referenced back in the HTML series' own accessibility coverage) — a border-based focus style would shift surrounding content slightly the moment an element received focus, a real, distracting visual side effect outline avoids entirely.
Not every visual property costs the same to render. box-shadow and border-radius are both real, GPU-friendly properties that don't trigger layout recalculation — genuinely safe to use freely. A background image, in contrast, has a real, direct network cost — every background-image is a real HTTP request, exactly like an <img> tag, and deserves the same size and format discipline covered in the HTML series' own responsive images guidance.
filter: a real, genuine caveat worth knowing before part 13
.product-card {
filter: drop-shadow(0 2px 8px rgba(0, 0, 0, 0.1));
}filter (including drop-shadow, a shadow variant that respects real transparency in a PNG or SVG, unlike box-shadow) is a real, useful visual tool — but it has a genuine, documented side effect worth knowing now: applying filter to an element creates a new CSS containing block, which changes how any position: fixed or position: absolute descendant behaves. Part 13 covers positioning in full, but this specific interaction is worth flagging early, since it's exactly the real bug class that once broke this very site's own header search modal.
Next: display — block, inline, inline-block, and none — the real property that determines how an element occupies space at all, before any layout system is involved.