Cards, Lists, and Media Objects
Introduction
Cards, lists, and media-object patterns appear in almost every modern UI: feeds, dashboards, profiles, search results, and settings pages. The goal is not just visual polish, but reusable structure, consistent spacing, and responsive behavior. This chapter covers practical CSS patterns you can apply across many product interfaces.
Prerequisites
- Basic Flexbox/Grid knowledge
- Box model and spacing fundamentals
- Responsive sizing and media handling basics
Design Goals for Reusable Components
For repeatable UI blocks, aim for:
- consistent spacing scale
- predictable typography hierarchy
- flexible media behavior
- clear hover/focus interaction feedback
- simple variant extension
Reusable patterns reduce CSS duplication and maintenance cost.
Card Component Basics
A solid base card:
.card {
display: grid;
gap: 0.75rem;
padding: 1rem;
border: 1px solid #e2e8f0;
border-radius: 12px;
background: #ffffff;
box-shadow: 0 4px 12px rgba(15, 23, 42, 0.06);
}Code explanation:
display: grid+gapgives clean internal spacing- border + soft shadow provides subtle separation
- radius and padding create a modern, readable surface
This is a good default for many product cards.
Card Header / Body / Footer Pattern
Keep these subregions explicit so variant cards stay predictable.
Interactive Card States
Code explanation:
- hover adds subtle lift
:focus-withinhelps keyboard users track active card context
Avoid turning every card into an aggressive animated component.
Card Grid Layout
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: 1rem;
}This creates responsive card columns with minimal breakpoint code.
List Styling Fundamentals
Default list styling is semantic but often needs visual tuning.
.list {
margin: 0;
padding: 0;
list-style: none;
}
.list > li {
padding: 0.75rem 0;
border-bottom: 1px solid #e2e8f0;
}Code explanation:
- removes browser default spacing/bullets
- applies consistent item rhythm and separators
If bullets/numbering are meaningful content, keep native semantics and style markers instead of removing them.
Marker Styling for Semantic Lists
.article-list li::marker {
color: #2563eb;
}This keeps list semantics while aligning visual brand language.
Compact vs Comfortable List Density
.list--compact > li {
padding-block: 0.4rem;
}
.list--comfortable > li {
padding-block: 0.9rem;
}Density variants help reuse one list structure in admin tables, feeds, and mobile menus.
Media Object Pattern
A classic media object pairs fixed media with flexible content.
Code explanation:
- fixed thumbnail width keeps visual consistency
- flexible body fills remaining space
min-width: 0prevents long text overflow issues
This pattern is ideal for comments, chat previews, notifications, and result rows.
Media Object with Actions
Useful for placing timestamps, tags, and contextual buttons cleanly.
Text Truncation in Cards/Lists
.truncate-1 {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}Use this for titles in dense UI where vertical expansion is undesirable.
For longer previews, prefer natural wrapping or controlled line-clamp strategy based on context.
Variant Strategy and Naming
Keep naming consistent:
- base:
.card - variants:
.card--interactive,.card--featured - parts:
.card__header,.card__body
Avoid deeply nested selectors tied to fragile DOM structure.
Clear naming is more maintainable than complex selector logic.
Tip
Build Reusable Primitives
A few strong primitives (card, list, media object) can power most UI screens with minor variants.
Responsive Adaptation
Media object can switch to stacked layout on very narrow widths:
@media (max-width: 420px) {
.media {
flex-direction: column;
}
.media__thumb {
width: 100%;
max-width: 220px;
}
}This prevents cramped horizontal layouts on small phones.
Common Mistakes
| Mistake | Why it hurts | Better approach |
|---|---|---|
| Building unique CSS for every card | Repetition and inconsistency | Use shared card base + small variants |
| Removing list semantics everywhere | Accessibility and structure loss | Keep semantic lists when content is list-like |
No min-width: 0 in media body | Text overflow in flex rows | Add explicit shrink allowance |
| Overly heavy shadows on all cards | Visual noise/perf cost | Keep subtle elevation scale |
| Fixed thumbnail sizes without responsive fallback | Layout break on narrow screens | Add mobile stacking/size rules |
Debugging Tips
When cards/lists/media rows look broken:
- inspect spacing layers (
padding,gap,margin) - verify list semantics and marker behavior
- check flex item shrink behavior (
min-width) - test long title/description overflow
- test narrow viewport for wrapping and interaction target size
Component stress-testing with long content catches most edge cases early.
Mini Exercise
- Build a card grid with 6 items using auto-fit/minmax
- Add interactive hover + focus-within states
- Build a semantic list with custom marker styling
- Build a media-object notification list with avatar + text + meta
- Add long-title test data and fix overflow cleanly
- Verify responsive behavior at phone/tablet/desktop widths
FAQ
Should every card have a shadow?
Not necessarily. Use shadow/elevation intentionally based on hierarchy and interaction importance.
Is it okay to remove ul bullets?
Yes for UI lists (menus, settings rows) if semantics remain intact. For article content lists, markers are often meaningful.
Why do media-object text columns overflow?
Flex children can resist shrinking. Adding min-width: 0 on the content column usually fixes this.
Should I use Grid or Flex for card internals?
Either can work. Grid + gap is often clean for vertical card structure; Flex is great for one-axis header/footer alignment.
How do I avoid too many card variants?
Start with one strong base and add only meaningful modifier classes tied to actual product states or hierarchy.