CSS object-fit and object-position
Lesson 59: CSS object-fit and object-position
Lesson Introduction
Have you ever visited a website where product images look squashed or stretched — a round face turned into an oval, or a portrait photo cropped in a weird way? These are image-fitting problems, and they are extremely common in real web development.
In this lesson, you will learn two powerful CSS properties — object-fit and object-position — that give you full, professional control over how images (and videos) display inside fixed-size containers. These are the exact tools used by Nigerian e-commerce sites like Jumia, Konga, and Flutterwave’s blog to display product and team photos cleanly, regardless of what shape the original image is.
What You Will Learn
By the end of this lesson, you will be able to:
- Understand why images distort and how to fix it
- Use all five values of
object-fitconfidently - Understand the difference between
containandcover - Use
object-positionto control which part of an image is shown - Combine
object-fitandobject-positionfor pixel-perfect image presentation - Apply these properties to real-world card grids, galleries, and profile pages
Prerequisite Concepts Recap
Before we start, let’s confirm you are comfortable with these ideas from earlier lessons:
- CSS
widthandheight— you know how to set fixed sizes on elements - CSS
overflow— you know thatoverflow: hiddenhides content that goes beyond a container’s bounds - The
<img>element — you know that images have their own natural dimensions from the image file itself - CSS
background-size(optional review) —object-fitworks similarly tobackground-sizebut applies to<img>and<video>elements directly
Section 1 — The Problem: Why Do Images Distort?
Understanding Natural Image Dimensions
Every image file has its own natural width and height — these are called its intrinsic dimensions. A photo taken on an Infinix phone might be 3000px × 4000px (portrait). A landscape banner might be 1920px × 400px (very wide). These dimensions are fixed inside the file itself.
When you put an image inside a fixed-size container in HTML, the browser has to decide: “This container is 200px × 200px square, but the image is 3000px × 4000px tall — what do I do?”
By default, the browser stretches or squashes the image to fit the container exactly. The result? Distortion.
Analogy — The Photograph in a Frame
Imagine you buy a square photo frame from Computer Village in Lagos, but the photo you want to put inside is tall and narrow (portrait). You have a few options:
- Squash the photo to fit the square — it looks distorted
- Shrink the entire photo until both sides fit inside the frame — there’s empty space on the sides
- Zoom in and crop the photo so it fills the frame — you lose some of the image edges
- Leave the photo at its natural size — it overflows the frame
CSS object-fit maps directly to these real-world decisions.
Seeing the Problem in Code
<img class="product-photo" src="tall-portrait.jpg" alt="Product">
.product-photo {
width: 200px;
height: 200px;
/* No object-fit — browser stretches the tall image into a square */
}
Expected output in browser: The tall portrait image is squashed horizontally to fit the 200px × 200px square, making everything look wide and distorted.
Section 2 — Introducing object-fit
What Is object-fit?
object-fit is a CSS property that controls how the content of a replaced element (an <img> or <video>) is resized to fit its container. It does not change the container’s size — it only controls how the image fills that container.
Think of it as instructions you give to the image: “Here is the frame. This is how I want you to sit inside it.”
Syntax
img {
width: 200px;
height: 200px;
object-fit: fill; /* or contain | cover | none | scale-down */
}
The Five Values
| Value | What It Does |
|---|---|
fill |
Stretches the image to fill the container exactly — may distort (default) |
contain |
Shrinks the image to fit entirely inside the container — no cropping, may show empty space |
cover |
Zooms the image to cover the container completely — maintains ratio, may crop edges |
none |
Displays the image at its natural size — may overflow or show empty space |
scale-down |
Picks the smaller result of either none or contain |
Section 3 — object-fit: fill (The Default)
What Is It?
fill is the default behaviour. The image is stretched (or squashed) in both directions until it fills the container exactly. It ignores the image’s natural proportions, which is why it causes distortion.
When Would You Use It?
Almost never intentionally. It is the default you are trying to escape from by using the other values. You rarely set object-fit: fill explicitly unless you want to override a more specific rule.
Example
.fill-demo {
width: 250px;
height: 150px;
object-fit: fill; /* Default behaviour — stretches to fill exactly */
border: 3px solid red;
}
<img class="fill-demo" src="nigerian-food.jpg" alt="Nigerian food">
Expected output in browser: The food image is stretched to exactly 250×150px regardless of its original shape. If the original was square, the result will look wide and squashed.
💡 Thinking Prompt: What do you think would happen if the image’s natural size was already 250×150px? Would
fillcause any distortion in that case?
Section 4 — object-fit: contain
What Is It?
contain shrinks (or grows) the image while preserving its natural proportions (aspect ratio), so that the entire image fits inside the container. No part of the image is ever cropped. However, if the image’s shape doesn’t match the container, you will see empty space on two sides — these empty areas show the container’s background colour.
Real-World Analogy
Imagine placing a tall portrait photo inside a wide landscape frame. The photo shrinks until its full height fits, leaving empty space on the left and right. You see the complete photo — but the frame is not fully filled.
Example
.contain-demo {
width: 300px;
height: 200px;
background-color: #f0f0f0; /* Shows as letterbox bars */
object-fit: contain;
border: 3px solid #009900;
}
<img class="contain-demo" src="adire-fabric.jpg" alt="Adire fabric">
Expected output in browser: The fabric image shrinks proportionally until it fits entirely within the 300×200 container. Grey bars appear on either the left/right or top/bottom (depending on the image’s natural shape). The full image is always visible.
When to Use contain
- Product images where you must show the entire item (shoes, fabric, electronics) without cropping anything off
- Logos and icons that must always appear complete
- Situations where showing the full image is more important than filling the container
Section 5 — object-fit: cover
What Is It?
cover is the most commonly used value in real web development. It zooms the image until it fully covers the container from edge to edge, while still preserving its natural proportions. Any parts of the image that overflow the container are simply clipped (hidden). The container is always perfectly filled with no empty space.
Real-World Analogy
Imagine printing a tall portrait photo large enough that its width exactly matches your wide frame. The full width is covered, but the top and bottom of the photo are hidden behind the frame edges. The frame looks completely filled — but some of the photo is cropped.
Example
.cover-demo {
width: 300px;
height: 200px;
object-fit: cover;
border: 3px solid #006400;
}
<img class="cover-demo" src="lagos-skyline.jpg" alt="Lagos skyline">
Expected output in browser: The skyline image fills the container perfectly with no empty space and no distortion. The image is cropped on the sides or top/bottom (wherever the overflow is), but the visible portion looks natural and undistorted.
When to Use cover
- Profile photos in circular or square containers (the most popular use case)
- Hero banners and section backgrounds
- Product card images in a grid layout — they all appear the same size without distortion
- Blog post thumbnails
⚠️ Important: With
cover, you are accepting that some parts of the image may be hidden (cropped). Useobject-position(Section 8) to control which part is kept visible.
Comparing contain vs cover Side by Side
<div class="demo-row">
<div>
<p>contain</p>
<img class="contain" src="ankara-pattern.jpg" alt="Ankara">
</div>
<div>
<p>cover</p>
<img class="cover" src="ankara-pattern.jpg" alt="Ankara">
</div>
</div>
.contain, .cover {
width: 200px;
height: 200px;
border: 3px solid #333;
}
.contain {
object-fit: contain;
background-color: #eee; /* Visible in the empty spaces */
}
.cover {
object-fit: cover;
/* No background needed — image always fills the container */
}
Expected output in browser: The contain image shows the full pattern but with grey bars. The cover image fills the square completely with the pattern — no bars, but edges may be cropped.
Section 6 — object-fit: none
What Is It?
none displays the image at its natural (intrinsic) size — completely ignoring the width and height set on the <img> element. If the image is larger than the container, it overflows. If it is smaller, empty space shows.
When Would You Use It?
Rarely — mainly when you intentionally want the image displayed at its natural pixel size, and you are controlling overflow yourself. It is mostly useful as a comparison tool to see what the original image size looks like.
Example
.none-demo {
width: 200px;
height: 150px;
object-fit: none;
overflow: hidden; /* Clip the overflow */
border: 3px solid orange;
}
<img class="none-demo" src="large-map-of-nigeria.jpg" alt="Nigeria map">
Expected output in browser: The image appears at its natural size (e.g., 800×600px). Only the portion that fits within the 200×150 container is visible — the rest is clipped by overflow: hidden. The visible portion is the top-left corner by default.
Section 7 — object-fit: scale-down
What Is It?
scale-down compares two options — none and contain — and picks whichever results in the smaller displayed size.
- If the image’s natural size is larger than the container → behaves like
contain(shrinks to fit) - If the image’s natural size is smaller than the container → behaves like
none(stays at natural size, not stretched)
Why Is This Useful?
It prevents small images from being blown up (stretched larger than their natural size), while still ensuring large images are shrunk to fit. This is ideal for situations where images come from different sources with unpredictable sizes.
Example
.scale-down-demo {
width: 300px;
height: 200px;
object-fit: scale-down;
background-color: #f5f5f5;
border: 2px dashed #999;
}
<!-- Small image: stays at natural size (no stretching) -->
<img class="scale-down-demo" src="small-logo-50px.png" alt="Small logo">
<!-- Large image: shrinks to fit (same as contain) -->
<img class="scale-down-demo" src="large-banner-1200px.jpg" alt="Large banner">
Expected output in browser (first image): The 50px logo stays at 50px — it is not stretched to fill the 300×200 container.
Expected output in browser (second image): The 1200px banner shrinks proportionally to fit inside the 300×200 container, same as contain.
Section 8 — Introducing object-position
What Is It?
object-position controls which part of the image is visible within the container after object-fit is applied.
When you use object-fit: cover or object-fit: none, part of the image is clipped. By default, the browser shows the centre of the image. But what if the important subject of the photo is at the top, or the left side, or 30% from the right? That is exactly what object-position lets you control.
Why It Matters
Imagine a team photo where everyone’s face is at the top of the image. With object-fit: cover in a square container, the browser shows the centre — which might be their chests, not their faces. object-position: top fixes this immediately.
Syntax
img {
object-fit: cover;
object-position: center; /* Default */
object-position: top; /* Show the top of the image */
object-position: bottom; /* Show the bottom */
object-position: left; /* Show the left side */
object-position: right; /* Show the right side */
object-position: top left; /* Show the top-left corner */
object-position: 30% 70%; /* 30% from left, 70% from top */
object-position: 50px 20px; /* 50px from left, 20px from top */
}
💡 The two values in
object-positionrepresent horizontal position first, then vertical position. This matches howbackground-positionworks.
Section 9 — object-position with Keyword Values
The Keyword Values
You can use any combination of these keywords:
- Horizontal:
left,center,right - Vertical:
top,center,bottom
When you write just one keyword, the other axis defaults to center.
Example — Controlling Which Part of an Image Shows
.portrait-card {
width: 200px;
height: 200px;
object-fit: cover;
border-radius: 50%; /* Make it circular */
border: 4px solid #006400;
}
.show-top { object-position: top; }
.show-center { object-position: center; } /* Default */
.show-bottom { object-position: bottom; }
.show-left { object-position: left; }
.show-right { object-position: right; }
<!-- Imagine each uses the same tall portrait of "Adaeze" -->
<img class="portrait-card show-top" src="adaeze.jpg" alt="Adaeze">
<img class="portrait-card show-center" src="adaeze.jpg" alt="Adaeze">
<img class="portrait-card show-bottom" src="adaeze.jpg" alt="Adaeze">
Expected output in browser:
show-top→ Adaeze’s face and shoulders are visible (best for most portrait photos)show-center→ the middle portion of the image is visibleshow-bottom→ Adaeze’s lower body is visible
💡 Thinking Prompt: If you had a group photo of all four Wizkid dancers, and only the right two are important, which
object-positionvalue would you use?
Two-Keyword Example
.corner-photo {
width: 250px;
height: 150px;
object-fit: cover;
object-position: top left; /* Show the top-left corner of the image */
}
Expected output in browser: When the image is cropped to fit the container, the top-left corner of the original image is what you see.
Section 10 — object-position with Length and Percentage Values
Using Percentages
Percentage values give you very precise control. The format is:
object-position: horizontal% vertical%;
0% 0%= top-left corner50% 50%= centre (same ascenter center)100% 100%= bottom-right corner30% 20%= 30% across from left, 20% down from top
Example — Precise Face Positioning
.staff-photo {
width: 180px;
height: 180px;
object-fit: cover;
border-radius: 50%;
object-position: 40% 15%; /* Face is slightly left of centre, near the top */
}
<img class="staff-photo" src="chukwuemeka-profile.jpg" alt="Chukwuemeka">
Expected output in browser: The circular crop shows Chukwuemeka’s face exactly where you positioned it — 40% across and 15% down from the top. No more cropped-out foreheads!
Using Pixel Values
object-position: 50px 30px;
/* Shows the part of the image starting 50px from the left and 30px from the top */
Using Negative Values
You can even use negative values to push the image in the opposite direction:
object-position: -20px 0;
/* Shifts the image 20px to the left, showing content that starts 20px into the image */
Section 11 — Combining object-fit and object-position
The Power Pair
object-fit decides how the image fills the container. object-position decides which part of the image is shown. Used together, they give you complete, professional image control.
Example — A Product Card Grid
/* The card container */
.product-card {
width: 220px;
background-color: white;
border-radius: 10px;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
overflow: hidden;
}
/* Fixed-size image area */
.product-card img {
width: 100%;
height: 200px;
object-fit: cover; /* Fill without distortion */
object-position: center; /* Show the centre (adjust per image if needed) */
display: block;
}
/* Card text */
.product-card .info {
padding: 12px;
}
<div class="product-card">
<img src="ankara-dress.jpg" alt="Ankara dress">
<div class="info">
<h3>Ankara Wrap Dress</h3>
<p>₦8,500</p>
</div>
</div>
<div class="product-card">
<img src="leather-bag.jpg" alt="Leather bag">
<div class="info">
<h3>Aba Leather Handbag</h3>
<p>₦12,000</p>
</div>
</div>
Expected output in browser: Both product cards are the exact same size. Both images fill their 220px × 200px area perfectly with no distortion and no empty space, regardless of each image’s original dimensions. The page looks professional and consistent.
Example — A Team Page with Circular Avatars
.team-avatar {
width: 140px;
height: 140px;
border-radius: 50%;
object-fit: cover;
object-position: top center; /* Show faces, not chests */
border: 4px solid #006400;
display: block;
margin: 0 auto 10px;
}
<figure>
<img class="team-avatar" src="bola-portrait.jpg" alt="Bola Adeyemi">
<figcaption>Bola Adeyemi — Lead Developer</figcaption>
</figure>
<figure>
<img class="team-avatar" src="funke-portrait.jpg" alt="Funke Okafor">
<figcaption>Funke Okafor — Product Designer</figcaption>
</figure>
Expected output in browser: Each team member’s photo appears in a perfectly circular frame, showing their face and shoulders. All circles are the same size regardless of the original photo dimensions.
Guided Exercises
Exercise 1 — The Jumia-Style Product Grid (Beginner)
Scenario: You are building the product listing page for an online Nigerian market called “Oja Online.” You have four product images of different shapes, but all cards must look identical.
Objective: Create four image cards, each 180px × 180px, that display images without distortion.
Steps:
- Create an HTML file with four
<div class="card">elements, each containing an<img>and a product name in a<p>tag - Use real image names or placeholder image services like
https://via.placeholder.com/300x400(tall),https://via.placeholder.com/400x200(wide) - Style the
.cardto have a fixed width, border, and padding - Style the
imgwithwidth: 100%,height: 180px, andobject-fit: cover
Hints:
- Set
display: blockon theimgto remove the small gap below it - Don’t forget
overflow: hiddenon the card to keep things tidy
Solution:
.card-grid {
display: flex;
gap: 20px;
flex-wrap: wrap;
}
.card {
width: 180px;
border: 1px solid #ddd;
border-radius: 8px;
overflow: hidden;
background-color: white;
}
.card img {
width: 100%;
height: 180px;
object-fit: cover;
object-position: center;
display: block;
}
.card p {
padding: 8px;
margin: 0;
font-size: 14px;
text-align: center;
}
<div class="card-grid">
<div class="card">
<img src="https://via.placeholder.com/300x500" alt="Tall product">
<p>Ankara Blouse</p>
</div>
<div class="card">
<img src="https://via.placeholder.com/600x200" alt="Wide product">
<p>Gele Head Wrap</p>
</div>
<div class="card">
<img src="https://via.placeholder.com/300x300" alt="Square product">
<p>Beaded Necklace</p>
</div>
<div class="card">
<img src="https://via.placeholder.com/400x350" alt="Near-square product">
<p>Leather Sandal</p>
</div>
</div>
Expected output in browser: All four cards are identical in size. All four images fill their 180px height without distortion. No empty bars appear.
Self-check Questions:
- What would happen if you changed
covertocontain? - What would you change if you wanted to ensure no image content is ever cropped?
Exercise 2 — Team Profile Circles (Intermediate)
Scenario: You are building the “About Us” page for a Lagos tech startup called “Abuja Stack Ltd.” The design team has given you portraits of five staff members — but the photos come in different shapes (some landscape, some portrait, some square).
Objective: Create circular profile avatars that all show faces correctly.
Steps:
- Create five
<figure>elements, each with an<img>and a<figcaption> - Style the image as a circle:
border-radius: 50%,width: 120px,height: 120px - Apply
object-fit: coverto fill the circle - Apply
object-position: top centerso faces show - Add a green border to each avatar
Solution:
.profile-grid {
display: flex;
gap: 30px;
flex-wrap: wrap;
justify-content: center;
}
figure {
text-align: center;
margin: 0;
}
.avatar {
width: 120px;
height: 120px;
border-radius: 50%;
object-fit: cover;
object-position: top center;
border: 4px solid #006400;
display: block;
}
figcaption {
margin-top: 8px;
font-size: 13px;
font-weight: bold;
color: #333;
}
<div class="profile-grid">
<figure>
<img class="avatar" src="https://via.placeholder.com/300x400" alt="Ngozi">
<figcaption>Ngozi Eze<br>CEO</figcaption>
</figure>
<figure>
<img class="avatar" src="https://via.placeholder.com/600x300" alt="Emeka">
<figcaption>Emeka Obi<br>CTO</figcaption>
</figure>
<figure>
<img class="avatar" src="https://via.placeholder.com/250x250" alt="Amina">
<figcaption>Amina Sule<br>Designer</figcaption>
</figure>
</div>
Expected output in browser: Three perfectly circular green-bordered avatars, all 120×120px, each showing the top portion (face area) of the photo regardless of the original image’s shape.
Self-check Questions:
- If a staff member’s photo had their face at the very bottom of the image, what
object-positionvalue would you use? - What would happen if you removed
border-radius: 50%but keptobject-fit: cover?
Exercise 3 — The Hero Banner Showcase (Advanced)
Scenario: You are building a homepage for a Nigerian cultural event website called “Afrobeats Festival Ibadan.” You need a full-width hero banner image that always looks great no matter the screen size, and a logo that never stretches.
Objective: Use object-fit: cover for the hero banner and object-fit: contain for the logo, with appropriate positioning.
Steps:
- Create a
.herosection withwidth: 100%,height: 400px - Place an
<img>inside it withwidth: 100%,height: 100%,object-fit: cover - Position the image to show the top portion:
object-position: top center - Create a
.logo-boxdiv withwidth: 150px,height: 80px - Place a logo
<img>inside withobject-fit: containand no background distortion
Solution:
/* Hero banner */
.hero {
width: 100%;
height: 400px;
overflow: hidden;
position: relative;
}
.hero img {
width: 100%;
height: 100%;
object-fit: cover;
object-position: top center;
display: block;
}
.hero-overlay {
position: absolute;
bottom: 30px;
left: 40px;
color: white;
text-shadow: 2px 2px 8px rgba(0,0,0,0.8);
}
.hero-overlay h1 { font-size: 36px; margin: 0; }
.hero-overlay p { font-size: 18px; margin: 5px 0 0; }
/* Logo */
.logo-box {
width: 150px;
height: 80px;
background-color: #f0f0f0;
border: 1px solid #ccc;
padding: 5px;
}
.logo-box img {
width: 100%;
height: 100%;
object-fit: contain;
object-position: center;
}
<section class="hero">
<img src="https://via.placeholder.com/1920x600" alt="Afrobeats festival crowd">
<div class="hero-overlay">
<h1>Afrobeats Festival Ibadan</h1>
<p>December 2025 · Mapo Hill</p>
</div>
</section>
<div class="logo-box">
<img src="https://via.placeholder.com/300x100" alt="Festival Logo">
</div>
Expected output in browser: A full-width 400px-tall hero image fills the section without distortion, showing the top portion. Overlaid text sits at the bottom-left. Below it, the logo fits cleanly in its box without stretching, with padding space around it if the proportions differ.
Code Challenges
Challenge 1 — Fix the Broken Product Page
Task: The code below produces stretched, distorted images. Add the correct object-fit property to fix it so images fill their containers cleanly without distortion. Do not change any other rule.
<div class="item"><img src="jollof-rice.jpg" alt="Jollof Rice"></div>
<div class="item"><img src="egusi-soup.jpg" alt="Egusi Soup"></div>
<div class="item"><img src="pounded-yam.jpg" alt="Pounded Yam"></div>
.item {
width: 200px;
height: 150px;
border: 2px solid #009900;
overflow: hidden;
}
.item img {
width: 100%;
height: 100%;
/* Your fix goes here */
}
Solution:
.item img {
width: 100%;
height: 100%;
object-fit: cover;
}
Challenge 2 — The Face-Cropping Problem
Task: A news website shows author profile pictures, but faces are being cut off at the top (the browser is showing the centre of tall portrait photos). Fix this using object-position without changing the existing object-fit: cover rule.
.author-pic {
width: 80px;
height: 80px;
border-radius: 50%;
object-fit: cover;
/* Your fix goes here */
}
Solution:
.author-pic {
width: 80px;
height: 80px;
border-radius: 50%;
object-fit: cover;
object-position: top center;
}
Challenge 3 — Show a Specific Part of an Image
Task: You have a wide landscape photo of the Lagos Island skyline (3000px × 800px). You are displaying it in a 400px × 300px container. You want to show the right side of the skyline — where the tallest buildings are. Use object-position to achieve this.
Solution:
.skyline {
width: 400px;
height: 300px;
object-fit: cover;
object-position: right center;
}
Or for more precise control:
.skyline {
width: 400px;
height: 300px;
object-fit: cover;
object-position: 80% 50%; /* 80% from the left shows the right portion */
}
Challenge 4 — Logo Display Without Stretching
Task: You are placing various partner logos into a uniform 160×60px container. Some logos are wide, some are square, some are tall. You want every logo to appear complete (no cropping) and centred, even if there is empty space around it. No logo should ever be stretched beyond its natural size.
Solution:
.partner-logo-box {
width: 160px;
height: 60px;
background-color: #fafafa;
border: 1px solid #eee;
display: flex;
align-items: center;
justify-content: center;
}
.partner-logo-box img {
width: 100%;
height: 100%;
object-fit: scale-down; /* Shrinks large logos; doesn't stretch small ones */
object-position: center;
}
Mini Project — The Oja Digital Market Gallery
Project Overview
You will build a complete, professionally styled Nigerian online market gallery page for “Oja Digital.” It will include a hero banner, a product image grid, and a team section — all using object-fit and object-position to ensure every image displays perfectly.
Stage 1 — Set Up the HTML Structure
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Oja Digital — Nigerian Online Market</title>
<link rel="stylesheet" href="oja-market.css">
</head>
<body>
<!-- Hero Banner -->
<section class="hero">
<img src="https://via.placeholder.com/1920x700/006400/ffffff?text=Oja+Digital+Market"
alt="Oja Digital Market banner">
<div class="hero-text">
<h1>Oja Digital</h1>
<p>Authentic Nigerian Goods — From Every State</p>
</div>
</section>
<!-- Product Grid -->
<main class="products">
<h2>Featured Products</h2>
<div class="product-grid">
<div class="product-card">
<img src="https://via.placeholder.com/300x500/cc6600/ffffff?text=Ankara" alt="Ankara fabric">
<div class="card-info">
<h3>Ankara Fabric (6 yards)</h3>
<p>₦4,500</p>
</div>
</div>
<div class="product-card">
<img src="https://via.placeholder.com/600x250/006400/ffffff?text=Gele" alt="Gele head wrap">
<div class="card-info">
<h3>Premium Gele</h3>
<p>₦6,200</p>
</div>
</div>
<div class="product-card">
<img src="https://via.placeholder.com/400x400/330099/ffffff?text=Bag" alt="Leather bag">
<div class="card-info">
<h3>Aba Leather Bag</h3>
<p>₦15,000</p>
</div>
</div>
<div class="product-card">
<img src="https://via.placeholder.com/350x600/cc0000/ffffff?text=Sandal" alt="Leather sandal">
<div class="card-info">
<h3>Handmade Sandal</h3>
<p>₦5,800</p>
</div>
</div>
</div>
</main>
<!-- Team Section -->
<section class="team">
<h2>Meet Our Team</h2>
<div class="team-grid">
<figure>
<img class="avatar" src="https://via.placeholder.com/300x450/006400/ffffff?text=CEO"
alt="Olumide Adeyemi">
<figcaption>Olumide Adeyemi<br><small>Founder & CEO</small></figcaption>
</figure>
<figure>
<img class="avatar" src="https://via.placeholder.com/450x300/cc6600/ffffff?text=CTO"
alt="Ngozi Okonkwo">
<figcaption>Ngozi Okonkwo<br><small>Chief Technology Officer</small></figcaption>
</figure>
<figure>
<img class="avatar" src="https://via.placeholder.com/300x300/330099/ffffff?text=CMO"
alt="Amina Bello">
<figcaption>Amina Bello<br><small>Head of Marketing</small></figcaption>
</figure>
</div>
</section>
<!-- Partner Logos -->
<section class="partners">
<h2>Our Partners</h2>
<div class="logo-strip">
<div class="logo-box">
<img src="https://via.placeholder.com/300x80/333333/ffffff?text=Partner+A" alt="Partner A">
</div>
<div class="logo-box">
<img src="https://via.placeholder.com/80x80/666666/ffffff?text=P+B" alt="Partner B">
</div>
<div class="logo-box">
<img src="https://via.placeholder.com/250x120/999999/ffffff?text=Partner+C" alt="Partner C">
</div>
</div>
</section>
</body>
</html>
Milestone 1 output: A plain, unstyled page with all sections visible but images in various distorted shapes.
Stage 2 — Base Styles and Hero Banner
/* oja-market.css */
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Arial', sans-serif;
background-color: #fafafa;
color: #222;
}
h2 {
text-align: center;
margin: 40px 0 20px;
color: #006400;
font-size: 28px;
}
/* ── HERO BANNER ── */
.hero {
width: 100%;
height: 420px;
position: relative;
overflow: hidden;
}
.hero img {
width: 100%;
height: 100%;
object-fit: cover;
object-position: center top; /* Show the top of the banner image */
display: block;
}
.hero-text {
position: absolute;
bottom: 40px;
left: 50%;
transform: translateX(-50%);
text-align: center;
color: white;
text-shadow: 2px 2px 10px rgba(0,0,0,0.7);
}
.hero-text h1 { font-size: 42px; }
.hero-text p { font-size: 18px; margin-top: 8px; }
Milestone 2 output: A full-width 420px-tall green hero banner with centred white text overlaid. The banner image fills the space without distortion.
Stage 3 — Product Grid
/* ── PRODUCT GRID ── */
.products {
max-width: 1000px;
margin: 0 auto;
padding: 0 20px 40px;
}
.product-grid {
display: flex;
flex-wrap: wrap;
gap: 20px;
justify-content: center;
}
.product-card {
width: 220px;
background-color: white;
border-radius: 10px;
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
overflow: hidden;
transition: transform 0.2s;
}
.product-card:hover {
transform: translateY(-4px);
}
.product-card img {
width: 100%;
height: 210px;
object-fit: cover;
object-position: center; /* Show the most representative centre portion */
display: block;
}
.card-info {
padding: 12px 14px;
}
.card-info h3 {
font-size: 15px;
margin-bottom: 6px;
color: #222;
}
.card-info p {
font-size: 16px;
font-weight: bold;
color: #006400;
}
Milestone 3 output: Four uniform product cards in a flex grid. All images are the same height (210px) and display without distortion regardless of their original dimensions. Cards gently lift on hover.
Stage 4 — Team and Partner Sections
/* ── TEAM SECTION ── */
.team {
background-color: #f0f5f0;
padding: 20px 0 50px;
}
.team-grid {
display: flex;
gap: 40px;
justify-content: center;
flex-wrap: wrap;
margin-top: 10px;
}
.team-grid figure {
text-align: center;
}
.avatar {
width: 130px;
height: 130px;
border-radius: 50%;
object-fit: cover;
object-position: top center; /* Always show face area */
border: 5px solid #006400;
display: block;
margin: 0 auto 10px;
}
figcaption {
font-size: 14px;
font-weight: bold;
color: #333;
line-height: 1.5;
}
figcaption small {
font-weight: normal;
color: #777;
}
/* ── PARTNER LOGOS ── */
.partners {
padding: 20px 0 60px;
}
.logo-strip {
display: flex;
gap: 30px;
justify-content: center;
flex-wrap: wrap;
margin-top: 10px;
}
.logo-box {
width: 180px;
height: 70px;
background-color: #fff;
border: 1px solid #ddd;
border-radius: 6px;
padding: 8px;
display: flex;
align-items: center;
justify-content: center;
}
.logo-box img {
width: 100%;
height: 100%;
object-fit: scale-down; /* Never stretch logos; shrink large ones */
object-position: center;
}
Milestone 4 (Final) output: The complete Oja Digital market page now shows:
- A polished full-width hero banner
- Uniform product cards in a flex grid with no distorted images
- Circular team avatars showing faces (not chests or feet)
- Partner logos cleanly contained in uniform boxes — none are stretched beyond their natural size
Common Beginner Mistakes
Mistake 1 — Applying object-fit to a <div> Instead of <img>
Wrong:
.card {
object-fit: cover; /* This does NOTHING on a div */
}
Problem: object-fit only works on replaced elements — elements that display external content like <img>, <video>, and <iframe>. It has no effect on <div>, <p>, or other container elements.
Correct: Apply object-fit to the <img> directly:
.card img {
object-fit: cover; /* Correct — on the img element */
}
Mistake 2 — Forgetting to Set Both width and height on the Image
Wrong:
img {
object-fit: cover;
/* No width or height set */
}
Problem: object-fit only does something when the image is constrained to a specific size. Without width and height, the image displays at its natural dimensions — and object-fit has nothing to act on.
Correct:
img {
width: 100%; /* or a fixed px value */
height: 200px; /* Must have a fixed height */
object-fit: cover;
}
Mistake 3 — Confusing contain and cover
Wrong mental model: “I want the image to cover my container, so I should use contain.”
Problem: The names are the opposite of what many beginners expect.
contain= contains the image inside the box → may show empty spacecover= covers the box completely → may crop the image
Memory tip: cover = like a book cover — it fills the whole space. contain = the image is contained within borders — nothing spills out.
Mistake 4 — Using object-position Without object-fit
Wrong:
img {
width: 200px;
height: 150px;
object-position: top;
/* No object-fit! */
}
Problem: Without object-fit: cover or object-fit: none, the image is stretched to fill the container (fill is the default), and object-position has nothing meaningful to shift.
Correct:
img {
width: 200px;
height: 150px;
object-fit: cover; /* First define how the image fills the space */
object-position: top; /* Then control which part is visible */
}
Mistake 5 — Swapping object-position Value Order
Wrong:
object-position: 50px top; /* Invalid — mixing px and keyword incorrectly */
Problem: When mixing lengths and keywords, the horizontal value must come first, then the vertical value.
Correct:
object-position: left 50px; /* horizontal: left; vertical: 50px */
object-position: 30% top; /* horizontal: 30%; vertical: top */
object-position: 50px 30px; /* horizontal: 50px; vertical: 30px */
Mistake 6 — Expecting scale-down to Always Behave Like contain
Wrong thinking: “scale-down and contain do the same thing.”
Problem: They only look the same when the image is larger than the container. When the image is smaller than the container:
containscales up the small image to fill the container (without cropping)scale-downkeeps the image at its natural size (does not scale up)
When to use which:
- Use
containwhen you want the image to always fill the container proportionally (allows upscaling) - Use
scale-downwhen you never want an image to appear larger than its natural size
Reflection Questions
Think about these carefully before moving to the next lesson:
- What is the key difference between
object-fit: containandobject-fit: cover? Give a real-world scenario where each would be the correct choice. - Why does
object-fithave no effect when applied to a<div>element? - If you have a portrait photo where the subject’s face is in the top-right corner, what
object-positionvalue would you use to ensure the face is always visible in a square crop? - What does
object-fit: scale-downdo differently fromobject-fit: containwhen the image is smaller than its container? - In a product grid, why is
covergenerally preferred overcontainfor product card images?
Completion Checklist
Before marking this lesson complete, confirm that you can:
- Explain why images distort when placed in a fixed-size container without
object-fit - Use
object-fit: filland explain when it causes problems - Use
object-fit: containand describe when empty space appears - Use
object-fit: coverand explain what gets cropped - Use
object-fit: noneand explain when the image overflows - Use
object-fit: scale-downand explain how it differs fromcontain - Use
object-positionwith keyword values (top,bottom,left,right,center) - Use
object-positionwith percentage values for precise control - Combine
object-fitandobject-positionin a product card layout - Apply circular avatar styling using
border-radius,object-fit: cover, andobject-position: top - Use
scale-downfor logo containers of varying image sizes - Completed all stages of the Oja Digital mini-project
Lesson Summary
In this lesson, you learned two properties that solve one of the most common real-world CSS problems — displaying images of different shapes cleanly inside fixed-size containers.
object-fit controls how the image fills its container. fill stretches (the distorted default). contain shrinks the image to fit completely with possible empty space. cover zooms to fill completely with possible cropping — the most widely used value. none shows the natural size. scale-down picks the smaller of none or contain, preventing small images from being upscaled.
object-position controls which part of the image is visible after fitting. It accepts keyword pairs (top, right, bottom, left, center), percentage pairs (30% 70%), and pixel values (50px 20px). The horizontal value always comes first.
Used together, these two properties give you complete, professional control over image presentation — the same control used by every major Nigerian and global e-commerce and media website.
Quick-Reference Card
/* ── object-fit ── */
img {
width: 200px;
height: 200px;
object-fit: fill; /* Stretches to fit — may distort (default) */
object-fit: contain; /* Shrinks to fit fully — may show empty space */
object-fit: cover; /* Zooms to fill — may crop edges */
object-fit: none; /* Natural size — may overflow */
object-fit: scale-down; /* Smaller of 'none' or 'contain' — never upscales */
}
/* ── object-position ── */
img {
object-fit: cover;
object-position: center; /* Default — shows centre of image */
object-position: top; /* Shows top portion */
object-position: bottom; /* Shows bottom portion */
object-position: left; /* Shows left portion */
object-position: right; /* Shows right portion */
object-position: top right; /* Shows top-right corner */
object-position: 30% 60%; /* 30% from left, 60% from top */
object-position: 50px 20px; /* 50px from left, 20px from top */
}
/* ── Most Common Pattern: Product Card ── */
.card img {
width: 100%;
height: 200px;
object-fit: cover;
object-position: center;
display: block;
}
/* ── Most Common Pattern: Circular Avatar ── */
.avatar {
width: 120px;
height: 120px;
border-radius: 50%;
object-fit: cover;
object-position: top center;
}
/* ── Most Common Pattern: Logo Box ── */
.logo-box img {
width: 100%;
height: 100%;
object-fit: scale-down;
object-position: center;
}
End of Lesson 59 — CSS object-fit and object-position