Cards are versatile UI components that group related content and actions. They’re fundamental to modern web design, appearing in dashboards, e-commerce, content feeds, and more. This guide covers card design patterns and implementation.
Basic Card Structure
Simple Card
<article class="card">
<div class="card-content">
<h3 class="card-title">Card Title</h3>
<p class="card-description">
This is the main content of the card. It can contain multiple paragraphs
or other HTML elements.
</p>
</div>
</article>
.card {
background: white;
border-radius: 12px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
overflow: hidden;
}
.card-content {
padding: 1.25rem;
}
.card-title {
font-size: 1.125rem;
font-weight: 600;
color: #111827;
margin: 0 0 0.5rem;
}
.card-description {
font-size: 0.9375rem;
color: #6b7280;
line-height: 1.5;
margin: 0;
}
Card with Image
Image Top
<article class="card">
<div class="card-image">
<img src="image.jpg" alt="Card image" loading="lazy">
</div>
<div class="card-content">
<span class="card-category">Category</span>
<h3 class="card-title">Card Title</h3>
<p class="card-description">Description text...</p>
<div class="card-meta">
<span>5 min read</span>
</div>
</div>
</article>
.card-image {
aspect-ratio: 16 / 9;
overflow: hidden;
}
.card-image img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.3s ease;
}
.card:hover .card-image img {
transform: scale(1.05);
}
.card-category {
display: inline-block;
font-size: 0.75rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
color: #2563eb;
margin-bottom: 0.5rem;
}
.card-meta {
display: flex;
gap: 1rem;
font-size: 0.8125rem;
color: #9ca3af;
margin-top: 1rem;
}
Image Overlay
.card-overlay {
position: relative;
}
.card-overlay .card-image {
position: absolute;
inset: 0;
}
.card-overlay .card-content {
position: relative;
height: 100%;
display: flex;
flex-direction: column;
justify-content: flex-end;
background: linear-gradient(to top, rgba(0,0,0,0.8), transparent);
color: white;
padding-top: 50%;
}
.card-overlay .card-title {
color: white;
}
.card-overlay .card-description {
color: rgba(255, 255, 255, 0.8);
}
Card with Actions
Action Buttons
<article class="card">
<div class="card-content">
<h3 class="card-title">Card Title</h3>
<p class="card-description">Description...</p>
</div>
<div class="card-actions">
<button class="btn btn-secondary btn-sm">Learn More</button>
<button class="btn btn-primary btn-sm">Get Started</button>
</div>
</article>
.card-actions {
display: flex;
gap: 0.5rem;
padding: 0.75rem 1.25rem 1.25rem;
border-top: 1px solid #f3f4f6;
margin-top: 0.5rem;
}
.card-actions .btn {
flex: 1;
}
Icon Actions
<article class="card">
<div class="card-content">
<div class="card-icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor">
<path d="M12 2L2 7l10 5 10-5-10-5z" />
</svg>
</div>
<h3 class="card-title">Feature Card</h3>
<p class="card-description">Description...</p>
</div>
</article>
.card-icon {
width: 48px;
height: 48px;
display: flex;
align-items: center;
justify-content: center;
background: #eff6ff;
color: #2563eb;
border-radius: 12px;
margin-bottom: 1rem;
}
.card-icon svg {
width: 24px;
height: 24px;
}
Card Variations
Interactive Card
.card-interactive {
cursor: pointer;
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.card-interactive:hover {
transform: translateY(-4px);
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
}
.card-interactive:active {
transform: translateY(-2px);
}
Selectable Card
.card-selectable {
cursor: pointer;
border: 2px solid transparent;
transition: border-color 0.2s, background 0.2s;
}
.card-selectable:hover {
border-color: #d1d5db;
}
.card-selectable.selected {
border-color: #2563eb;
background: #eff6ff;
}
.card-selectable input[type="checkbox"],
.card-selectable input[type="radio"] {
position: absolute;
opacity: 0;
}
Stat Card
.card-stat {
display: flex;
align-items: center;
gap: 1rem;
}
.card-stat .stat-value {
font-size: 2rem;
font-weight: 700;
color: #111827;
}
.card-stat .stat-label {
font-size: 0.875rem;
color: #6b7280;
}
.card-stat .stat-change {
font-size: 0.8125rem;
font-weight: 500;
}
.card-stat .stat-change.positive {
color: #10b981;
}
.card-stat .stat-change.negative {
color: #ef4444;
}
Card Grid Layouts
Responsive Grid
.card-grid {
display: grid;
gap: 1.5rem;
grid-template-columns: repeat(1, 1fr);
}
@media (min-width: 640px) {
.card-grid {
grid-template-columns: repeat(2, 1fr);
}
}
@media (min-width: 1024px) {
.card-grid {
grid-template-columns: repeat(3, 1fr);
}
}
@media (min-width: 1280px) {
.card-grid {
grid-template-columns: repeat(4, 1fr);
}
}
Auto-Fit Grid
.card-grid-auto {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 1.5rem;
}
Masonry Layout (CSS Columns)
.card-grid-masonry {
column-count: 1;
column-gap: 1.5rem;
}
.card-grid-masonry .card {
break-inside: avoid;
margin-bottom: 1.5rem;
}
@media (min-width: 640px) {
.card-grid-masonry {
column-count: 2;
}
}
@media (min-width: 1024px) {
.card-grid-masonry {
column-count: 3;
}
}
Card Patterns by Use Case
Product Card
<article class="card product-card">
<div class="product-image">
<img src="product.jpg" alt="Product name">
<span class="product-badge">Sale</span>
</div>
<div class="product-content">
<span class="product-category">Category</span>
<h3 class="product-title">Product Name</h3>
<div class="product-rating">โ
โ
โ
โ
โ (4.2)</div>
<div class="product-price">
<span class="price-current">$49.99</span>
<span class="price-original">$79.99</span>
</div>
<button class="btn btn-primary btn-block">Add to Cart</button>
</div>
</article>
User Card
<article class="card user-card">
<div class="user-avatar">
<img src="avatar.jpg" alt="User name">
</div>
<div class="user-content">
<h3 class="user-name">John Doe</h3>
<p class="user-title">Senior Developer</p>
<p class="user-bio">Building great products...</p>
<div class="user-stats">
<span><strong>120</strong> Posts</span>
<span><strong>2.5k</strong> Followers</span>
</div>
</div>
<div class="user-actions">
<button class="btn btn-primary btn-sm">Follow</button>
<button class="btn btn-secondary btn-sm">Message</button>
</div>
</article>
Notification Card
<div class="card notification-card">
<div class="notification-icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor">
<path d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9" />
</svg>
</div>
<div class="notification-content">
<p class="notification-message">
<strong>Sarah</strong> mentioned you in a comment
</p>
<span class="notification-time">2 minutes ago</span>
</div>
</div>
Card Elevation
Shadow Levels
.card-shadow-sm {
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
}
.card-shadow-md {
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.07), 0 2px 4px rgba(0, 0, 0, 0.05);
}
.card-shadow-lg {
box-shadow: 0 10px 15px rgba(0, 0, 0, 0.1), 0 4px 6px rgba(0, 0, 0, 0.05);
}
.card-shadow-xl {
box-shadow: 0 20px 25px rgba(0, 0, 0, 0.1), 0 10px 10px rgba(0, 0, 0, 0.04);
}
/* Interactive elevation */
.card-interactive.card-shadow-sm:hover {
box-shadow: 0 10px 15px rgba(0, 0, 0, 0.1);
}
Border Variant
.card-border {
border: 1px solid #e5e7eb;
box-shadow: none;
}
.card-border:hover {
border-color: #d1d5db;
}
Mobile Considerations
@media (max-width: 640px) {
.card-content {
padding: 1rem;
}
.card-actions {
padding: 0.75rem 1rem 1rem;
flex-direction: column;
}
.card-grid {
gap: 1rem;
}
}
Accessibility
<!-- Clickable card with proper semantics -->
<article
class="card card-interactive"
tabindex="0"
role="button"
aria-label="Article: Card Title"
>
<div class="card-image">
<img src="image.jpg" alt="">
</div>
<div class="card-content">
<h3 class="card-title">Card Title</h3>
</div>
</article>
.card-interactive:focus-visible {
outline: 2px solid #2563eb;
outline-offset: 2px;
}
Best Practices
Do
- Use consistent padding
- Include clear visual hierarchy
- Add hover/focus states
- Use meaningful images
- Keep text concise
Don’t
- Overcrowd cards
- Use inconsistent sizes
- Forget mobile layouts
- Skip alt text
- Make cards too complex
Summary
Cards are versatile building blocks:
- Basic: Content + optional image
- Actions: Buttons, links, icons
- Interactive: Hover effects, selection
- Grid: Responsive layouts
- Types: Product, user, notification, stat
Key implementation tips:
- Consistent spacing
- Clear hierarchy
- Interactive feedback
- Mobile responsive
- Accessible markup
Use cards thoughtfully - they’re everywhere in modern UI!
Comments