Styling a Real Card

Everything you know, combined into one beautiful component

10 min read

Time to put your skills together. The card is one of the most common patterns on the web: a self-contained box with an image, a title, some text, and a link. Product cards, article previews, profile cards, they are everywhere. By the end of this lesson you will have built one from scratch, and you will understand every line.

The HTML

A card starts as simple, honest HTML:

<div class="card">
  <img class="card-image" src="sunset.jpg" alt="Sunset over the sea">
  <div class="card-body">
    <h3 class="card-title">Evening at the Coast</h3>
    <p class="card-text">Golden light, calm water, and a walk to remember.</p>
    <a class="card-link" href="story.html">Read the story</a>
  </div>
</div>

Notice the structure: the image sits at the top, and everything else lives inside card-body. That inner wrapper exists for one reason: we want padding around the text but we want the image to reach the card's edges. Padding on the outer card would push the image inward too.

The card shell

.card {
  max-width: 320px;
  background-color: white;
  border: 1px solid #e2e2e2;
  border-radius: 12px;
  overflow: hidden;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}

You know almost all of this already: a soft border, rounded corners, a faint shadow. The one new property is overflow: hidden;. Without it, the square-cornered image would poke past the card's rounded corners at the top. With it, anything outside the rounded shape is clipped away, so the image follows the curve.

The image and the body

.card-image {
  width: 100%;
  height: 180px;
  object-fit: cover;
  display: block;
}

.card-body {
  padding: 16px;
}

The image fills the card's width and keeps a fixed height, and object-fit: cover; tells the browser to crop the photo neatly instead of squashing it. Every photo, whatever its shape, will fill the space handsomely.

The text and the link

.card-title {
  margin: 0 0 8px 0;
  font-size: 1.25rem;
  color: #1a1a2e;
}

.card-text {
  margin: 0 0 16px 0;
  color: #555555;
  line-height: 1.5;
}

.card-link {
  color: steelblue;
  font-weight: bold;
  text-decoration: none;
}

.card-link:hover {
  text-decoration: underline;
}

Two small design choices worth noticing. The body text is a softer gray than the title, which creates a visual hierarchy: your eye reads the title first, then the text. And the link only shows its underline on hover, staying tidy until the visitor shows interest.

The finishing touch

Remember the lift effect from the transitions lesson? This is where it belongs:

.card {
  transition: transform 0.2s, box-shadow 0.2s;
}

.card:hover {
  transform: translateY(-4px);
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.12);
}

Hover over the card and it rises gently to meet the cursor. Step back and look at what you built: box model, borders, radius, shadows, typography, hover states, and transitions, all working together in one component. That is not a toy example. That is a production-quality card you can use on your website today.

Challenge: build a second card with your own photo and words, then change one thing to make it yours. A different accent color, a bolder shadow, rounder corners. Tweaking a working example is one of the fastest ways to learn design.

Quick check

Q1 Why does the card use overflow: hidden;?

Q2 Why is the padding on .card-body instead of .card?

Want to save your progress? It's free.

Create a free account