# Bootstrap Images: Every Class You Need, Plus What Bootstrap Won't Do for You

> Bootstrap image classes explained: img-fluid, img-thumbnail, alignment, figures, cards and carousels, plus the responsive srcset it leaves to you.

Canonical page: https://www.imageguide.dev/guides/bootstrap-images/

Published: 2026-08-21. Updated: 2026-10-17.

Publisher: ImageGuide, published by Sirv. [Editorial method](https://www.imageguide.dev/about/#how-we-write).

## Quick answer

Bootstrap's img-fluid class makes an image fit its container, and img-thumbnail adds thumbnail styling. Neither class compresses the file or creates responsive source images. Add intrinsic dimensions, srcset and sizes, then choose suitable loading behavior to make the image efficient as well as responsive.

Reference for this answer: [Bootstrap image documentation](https://getbootstrap.com/docs/5.3/content/images/).

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:

```html
<img src="photo.jpg" class="img-fluid" alt="Team photo from the offsite">
```

`.img-fluid` applies exactly two declarations:

```css
.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:

1. It never scales an image **up** beyond its intrinsic size. A 400px-wide photo in a 800px column stays 400px wide.
2. 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`

```html
<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:

```html
<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:

```html
<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:

```html
<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:

```html
<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:

```html
<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](/guides/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:

```html
<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 corners
- `rounded-3` — larger radius
- `rounded-circle` — perfect circle (the old `.rounded-circle` replaced Bootstrap 4's `.rounded-circle` behavior 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:

```html
<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:

1. Without explicit `width` and `height` attributes, a card grid where images load at different times will jump as each image arrives — more on this below.
2. 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-ratio` plus `object-fit: cover`).

### Carousel

Carousel slides want fixed dimensions so the component does not change height between slides:

```html
<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](/guides/core-web-vitals-images).

### Navbar

Navbar brand logos are the classic alignment headache. Keep them short and constrain the height:

```html
<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`

```html
<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](/guides/responsive-images-complete-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`:

```html
<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`:

```html
<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](/guides/webp-avif-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:

```html
<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:

```css
.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](/guides/core-web-vitals-images) has the full checklist.

## Lazy Loading

Native lazy loading is one attribute:

```html
<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"` with `width` and `height`.** 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](/guides/lazy-loading-strategies).

## 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:

```scss
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:

1. **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.
2. **Generate width variants.** Something must produce the 640/1280/1920 files your `srcset` references — a build step, or a CDN that derives variants on demand.
3. **Compress once, centrally.** Batch pipelines keep quality consistent; our [batch processing workflows guide](/guides/batch-image-processing-workflows) compares approaches.
4. **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:

```html
<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](https://sirv.com/help/articles/sirv-media-viewer/) on top of the same masters, and marketing teams can retouch or cut out backgrounds themselves in [Sirv Studio](https://www.sirv.studio/) without touching the codebase. If your Bootstrap project has outgrown hand-resized folders, you can [try Sirv free](https://my.sirv.com/#/signup) and point it at your existing images.

5. **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.

## Sources

- [Images, Bootstrap documentation](https://getbootstrap.com/docs/5.3/content/images/)
