
Bootstrap Images: Every Class You Need, Plus What Bootstrap Won't Do for You
A practical guide to bootstrap images: img-fluid, img-thumbnail, alignment classes, figures, cards, carousels, lazy loading, and responsive srcset patterns that Bootstrap 5 does not handle for you.
Bootstrap ships a small set of image classes, and they solve maybe 20% of the real work of putting bootstrap images on a page. The other 80% — serving the right size to each device, avoiding layout shift, compressing files — is on you. This guide covers both halves: every class you will actually use, and the responsive-image plumbing that Bootstrap 5 deliberately leaves out.
The single most important thing to understand up front: Bootstrap does not generate srcset or sizes for you. A img-fluid image still downloads one file at whatever resolution you point at it. Everything else in this guide builds on that fact.
The Core Classes
.img-fluid
This is the class you will use most:
<img src="photo.jpg" class="img-fluid" alt="Team photo from the offsite">
.img-fluid applies exactly two declarations:
.img-fluid {
max-width: 100%;
height: auto;
}
That is the whole thing. max-width: 100% means the image never renders wider than its container. height: auto keeps the aspect ratio intact as the width shrinks. Together they make an image scale down gracefully inside any column, card, or container.
Two things .img-fluid does not do:
- It never scales an image up beyond its intrinsic size. A 400px-wide photo in a 800px column stays 400px wide.
- It does nothing about which file loads. A 4000px original still downloads in full on a phone.
If you want an image to fill its container even when that means upscaling, use w-100 instead — but check the result at large sizes, because upscaled photos look soft.
.img-thumbnail
<img src="photo.jpg" class="img-thumbnail" alt="Profile thumbnail">
Adds a rounded 1px border, some padding, and a white background — the classic framed-thumbnail look. It inherits max-width: 100% from the reboot styles, so it is safe in narrow columns. It is purely decorative styling; it does not resize the underlying file. A thumbnail gallery built with .img-thumbnail should still point at genuinely small image files, not scaled-down versions of originals.
Alignment
Images are inline elements by default, so alignment behaves differently depending on whether you treat them as blocks or floats.
Centering
The most common pattern for a standalone centered image:
<img src="logo.svg" class="mx-auto d-block" alt="Company logo" width="200" height="60">
d-block makes the image a block element so margins apply; mx-auto centers it horizontally. For an image inside a paragraph of text, wrap it and center the wrapper instead:
<div class="text-center">
<img src="badge.png" alt="Certification badge" width="120" height="120">
</div>
Floating
Bootstrap 5 replaced the old float-left / float-right with directional utilities:
<img src="chart.png" class="float-start me-3 mb-2" alt="Quarterly chart" width="320" height="180">
<p>Body text wraps around the floated image...</p>
float-start aligns left in LTR layouts, float-end right. Add margin utilities (me-3, mb-2) so text does not touch the image. Clear the float afterward with a <div class="clearfix"></div> when the next section must start below the image.
On small screens a floated image often looks cramped. A common pattern is to float only from the md breakpoint up:
<img src="chart.png" class="float-md-start me-md-3 mb-2" alt="Quarterly chart" width="320" height="180">
Below md, the image sits inline at full column width; above it, text wraps.
Figures and Captions
For images that need captions, use the figure component rather than hand-rolling a div:
<figure class="figure">
<img src="architecture.jpg" class="figure-img img-fluid rounded" alt="System architecture diagram" width="1200" height="675">
<figcaption class="figure-caption text-center">
Figure 1. Request flow through the API gateway.
</figcaption>
</figure>
.figure-img adds bottom spacing, .figure-caption styles the caption text smaller and muted. This markup also helps accessibility and SEO: screen readers announce the association between image and caption, and search engines get extra context about the image subject. If caption copy matters for search, pair it with descriptive alt text — our image alt text guide covers how the two differ.
Rounded Corners and Circles
Bootstrap 5 has border-radius utilities that work on any element, including images:
<img src="avatar.jpg" class="rounded" alt="Avatar" width="64" height="64">
<img src="avatar.jpg" class="rounded-circle" alt="Avatar" width="64" height="64">
<img src="card-top.jpg" class="rounded-top" alt="Cover" width="400" height="200">
rounded— small radius on all cornersrounded-3— larger radiusrounded-circle— perfect circle (the old.rounded-circlereplaced Bootstrap 4’s.rounded-circlebehavior of.img-circle; same idea)rounded-top/rounded-bottom/rounded-start/rounded-end— radius on specific sides
One caution: rounded-circle crops visually by clipping, not by trimming pixels. Feed it a square source image, or faces drift off-center. Cropping to a square before upload beats fighting it with CSS object-position hacks.
Images Inside Components
Cards
Card images sit at the top edge and need their top corners clipped to match the card’s radius:
<div class="card" style="width: 18rem;">
<img src="product.jpg" class="card-img-top" alt="Trail running shoe" width="600" height="400" loading="lazy">
<div class="card-body">
<h5 class="card-title">Trail Runner Pro</h5>
<p class="card-text">Lightweight grip for mixed terrain.</p>
</div>
</div>
.card-img-top handles the corner clipping for you. Two pitfalls:
- Without explicit
widthandheightattributes, a card grid where images load at different times will jump as each image arrives — more on this below. - Cards in a horizontal row look broken when their images have different aspect ratios. Crop sources to one ratio before upload, or enforce one with CSS (
aspect-ratioplusobject-fit: cover).
Carousel
Carousel slides want fixed dimensions so the component does not change height between slides:
<div id="heroCarousel" class="carousel slide" data-bs-ride="carousel">
<div class="carousel-inner">
<div class="carousel-item active">
<img src="slide-1.jpg" class="d-block w-100" alt="New collection preview" width="1920" height="1080">
</div>
<div class="carousel-item">
<img src="slide-2.jpg" class="d-block w-100" alt="Store interior" width="1920" height="1080">
</div>
</div>
</div>
Note d-block w-100, not img-fluid — the carousel needs block-level, full-width images. All slides should share identical dimensions. Serve carousel images pre-sized to roughly the largest rendering width; a 5000px hero in a carousel is the most common oversized-image mistake we see in audits.
Do not lazy-load the first slide. It is usually your LCP element, and deferring it directly hurts your Core Web Vitals image scores.
Navbar
Navbar brand logos are the classic alignment headache. Keep them short and constrain the height:
<nav class="navbar navbar-light bg-light">
<div class="container">
<a class="navbar-brand" href="/">
<img src="logo.svg" alt="Acme home" width="120" height="32">
</a>
</div>
</nav>
Set explicit width and height so the navbar does not reflow while the logo loads. SVG works best here because it stays crisp at any density without multiple files.
The Key Insight: Bootstrap Does Not Do Responsive Sources
Every class above controls layout. None of them control which file the browser downloads. On a 375px phone, an img-fluid hero still fetches the same 1920px JPEG that a 1440px desktop fetches. That mismatch is typically the largest payload on a Bootstrap page.
The fix is native HTML, and it works fine inside Bootstrap layouts because Bootstrap only styles the resulting element.
srcset and sizes
<img
src="hero-1280.webp"
srcset="hero-640.webp 640w,
hero-1280.webp 1280w,
hero-1920.webp 1920w"
sizes="(max-width: 992px) 100vw, 50vw"
class="img-fluid"
alt="Mountain trail at sunrise"
width="1920" height="1080"
loading="lazy">
How to read this: srcset lists candidate files with their intrinsic widths. sizes tells the browser how wide the image will render — here, full viewport width below the lg breakpoint (where a Bootstrap column spans the row) and half viewport above it (a typical col-lg-6). The browser picks the smallest file that still looks sharp.
The sizes value is where people go wrong, because it must describe your layout, and in Bootstrap the layout is the grid. Rough mapping:
| Layout | Good sizes hint |
|---|---|
| Full-width hero | 100vw |
col-12 col-lg-6 two-column |
(min-width: 992px) 50vw, 100vw |
| Three cards per row on desktop | (min-width: 992px) 33vw, 100vw |
| Fixed-width sidebar image | 300px |
Get sizes approximately right and browsers pick well. Get it wrong (or omit it — the default is 100vw) and browsers overshoot, downloading desktop files for phones. Our complete responsive images guide goes deeper on descriptor math.
Generating those width variants is a build-step job or a CDN job. Doing it by hand for every image does not survive contact with a real site.
Art Direction with picture
When different breakpoints need differently cropped images — not just differently sized ones — use picture:
<picture>
<source media="(max-width: 767px)" srcset="hero-mobile.webp" width="750" height="1000">
<source media="(min-width: 768px)" srcset="hero-desktop.webp" width="1920" height="800">
<img src="hero-desktop.webp" class="img-fluid" alt="Product lineup" width="1920" height="800">
</picture>
Typical Bootstrap use cases: a tall portrait crop for mobile heroes and a wide crop for desktop, or a simplified diagram for narrow screens. Note that the width/height attributes belong on the img fallback, and each source’s dimensions should match its own aspect ratio so the browser reserves correct space.
You can combine format switching and art direction in one picture:
<picture>
<source type="image/avif" srcset="hero.avif" width="1600" height="900">
<source type="image/webp" srcset="hero.webp" width="1600" height="900">
<img src="hero.jpg" class="img-fluid" alt="Workshop space" width="1600" height="900">
</picture>
Browsers pick the first source they support: AVIF, then WebP, then the JPEG fallback. AVIF typically lands 20–40% smaller than a comparable WebP, though encoding is slower; see our WebP vs AVIF vs JPEG XL comparison for trade-offs.
Preventing Layout Shift
Cumulative Layout Shift is where most Bootstrap pages quietly bleed score. The mechanism: the browser reserves zero space for an image until it starts loading, then pushes everything below it down.
The fix costs one line per image:
<img src="chart.png" class="img-fluid" width="1200" height="675" alt="Revenue chart">
With both attributes present, the browser computes the aspect ratio before load and reserves the exact box. This works together with height: auto from .img-fluid — modern browsers derive aspect-ratio from the attributes and let CSS scale the box proportionally. Setting the attributes does not force a 1200px render; it only declares the shape.
For images whose rendered ratio differs from the source ratio (cropped card covers, for instance), declare the ratio in CSS instead:
.card-img-cover {
aspect-ratio: 3 / 2;
object-fit: cover;
width: 100%;
}
Audit trick: run Lighthouse, and if CLS shows entries like “image elements [CLS] do not have explicit width and height,” fix those first. They are free wins. Our Core Web Vitals guide has the full checklist.
Lazy Loading
Native lazy loading is one attribute:
<img src="gallery-12.webp" class="img-fluid" loading="lazy" width="800" height="533" alt="Gallery view">
Bootstrap 5 dropped jQuery and ships no JavaScript lazy loader — correctly, because loading="lazy" is supported in every current browser and needs no library. Old tutorials recommending data-src swap-ins with Lozad or lazysizes are obsolete for new work.
Rules that keep lazy loading from backfiring:
- Never lazy-load above-the-fold images, especially heroes and carousel first slides. Deferring the LCP image is a self-inflicted regression.
- Always pair
loading="lazy"withwidthandheight. Lazy images without reserved space cause more shift, because the shift happens later and closer to user interaction. - Below-the-fold grids, article bodies, and long galleries are ideal candidates.
For finer control over the loading threshold or priority hints, see our lazy loading strategies guide.
Grid Pitfalls
A few failure modes show up again and again when bootstrap images meet the grid:
Overflowing columns. An image with an intrinsic width wider than its column overflows horizontally unless something constrains it. Any image that lives in a column should carry img-fluid (or be covered by a global rule). One global safety net many teams add:
img {
max-width: 100%;
height: auto;
}
Bootstrap’s reboot already includes this for img, svg, video — so overflow usually comes from third-party embeds or overridden styles, not plain images. Check there first when a page scrolls sideways.
Stretched images. The opposite problem: w-100 on a small source image stretches it past its intrinsic size and it turns blurry. Use w-100 only when the source is at least as large as the biggest rendering.
Uneven card rows. Flexbox stretch makes cards equal height, but their images are not. Fix at the source level (crop to a common ratio) or the CSS level (aspect-ratio + object-fit: cover), not by fiddling with per-card margins.
Row gutters and captions. A figure inside a row without g-0 gets gutter padding that makes the image narrower than sibling content. Decide intentionally whether the image aligns to the gutter or inside it.
An Optimization Workflow That Fits Bootstrap
Classes and attributes handle layout. File weight is a separate pipeline. A workflow that holds up in practice:
- Pick modern formats. Encode delivery images as WebP at minimum; add AVIF where your encoder supports it. Both beat JPEG by double-digit percentages at matched quality.
- Generate width variants. Something must produce the 640/1280/1920 files your
srcsetreferences — a build step, or a CDN that derives variants on demand. - Compress once, centrally. Batch pipelines keep quality consistent; our batch processing workflows guide compares approaches.
- Let a CDN do resizing. Instead of pre-generating variants, store one high-quality master and let URL parameters produce each size on the fly. With Sirv, the same master serves every breakpoint:
<img
src="https://youraccount.sirv.com/photos/hero.jpg?w=1280&q=80&format=webp"
srcset="https://youraccount.sirv.com/photos/hero.jpg?w=640&q=80&format=webp 640w,
https://youraccount.sirv.com/photos/hero.jpg?w=1280&q=80&format=webp 1280w,
https://youraccount.sirv.com/photos/hero.jpg?w=1920&q=80&format=webp 1920w"
sizes="(min-width: 992px) 50vw, 100vw"
class="img-fluid"
width="1920" height="1080"
loading="lazy"
alt="Studio workspace">
The CDN resizes, compresses, converts format, and caches each variant — no build step, no variant zoo in storage. This pairs well with interactive presentation too: product pages that need zoomable galleries or 360 spins can layer the Sirv Media Viewer on top of the same masters, and marketing teams can retouch or cut out backgrounds themselves in Sirv Studio without touching the codebase. If your Bootstrap project has outgrown hand-resized folders, you can try Sirv free and point it at your existing images.
- Verify. Run Lighthouse on a throttled mobile profile and confirm: no missing dimension warnings, LCP image not lazy-loaded, transfer sizes in the hundreds-of-KB range for heroes rather than megabytes.
Quick Reference
| Task | Class / attribute |
|---|---|
| Scale down within container | img-fluid |
| Framed thumbnail | img-thumbnail |
| Center standalone | mx-auto d-block |
| Center inline | wrapper with text-center |
| Float left / right | float-start / float-end |
| Caption | figure + figure-caption |
| Circle avatar | rounded-circle |
| Card cover | card-img-top |
| Carousel slide | d-block w-100 |
| Responsive sources | srcset + sizes (manual) |
| Format fallbacks | picture + source |
| Defer offscreen | loading="lazy" |
| Prevent CLS | width + height attributes |
Takeaways
Bootstrap gives you layout classes; the web platform gives you responsive sources; performance comes from combining them deliberately. The recurring theme of this guide: every Bootstrap image class answers “how does this render,” and none answer “what downloads.” Close that gap with srcset/sizes or CDN resizing, stamp width/height on everything, lazy-load only what is offscreen, and a stock Bootstrap template can hit the same image-performance numbers as a hand-tuned framework setup.