The <img> tag
An image is added with a single self-closing <img> tag. It needs two things: src (where the file is) and alt (a text description).
src can be a file in your project (images/cat.jpg) or a full URL (https://…). There's no closing </img> — it's a void element.
Alt text: the most important attribute
Alt text is read aloud by screen readers, shown if the image fails to load, and used by search engines. There are three cases:
| Case | What to write | Example |
|---|---|---|
| Meaningful image | Describe what it shows, briefly | alt="Students working at laptops" |
| Decorative image | Empty alt — tells screen readers to skip it | alt="" |
| Image that's a link/button | Describe the destination or action | alt="Home" |
Choosing the right format
The format decides quality, file size, and what's possible (transparency, animation). Pick by the kind of image.
| Format | Best for | Notes |
|---|---|---|
| JPG / JPEG | Photographs | Small files, no transparency. Lossy — don't re-save repeatedly. |
| PNG | Graphics, logos, screenshots, transparency | Lossless, larger files. Supports transparent backgrounds. |
| WebP | Almost everything (modern default) | 30–35% smaller than JPG/PNG at similar quality. Wide support. |
| AVIF | Photos where size matters most | Even smaller than WebP. Newer; check browser support. |
| SVG | Logos, icons, simple illustrations | Vector — infinitely scalable, tiny, crisp at any size. |
| GIF | Short, simple animations only | Large & only 256 colors. For real video, use <video>. |
Make them fast
Images are usually the heaviest thing on a page. A 4000×3000 photo straight from a phone can be 5 MB; the same photo sized and compressed for the web is often under 150 KB — visually identical, ~30× faster.
Three things to always do
- Resize to the size it actually displays (don't ship a 4000px image into a 400px box).
- Compress with a tool like Squoosh, TinyPNG, or your image editor's “export for web.”
- Lazy-load below-the-fold images so they load only when needed.
<img src="hero.webp" alt="…" width="800" height="500" reserve space (stops layout jump) loading="lazy"> load only when near the viewport
width and height (or an aspect-ratio in CSS). It reserves the space before the image loads, so the page doesn't jump around — a metric called Cumulative Layout Shift.Responsive images
An image shouldn't overflow its container on a phone. The one CSS rule every image needs:
img { max-width: 100%; height: auto; } never wider than its box; keep proportions
For real performance, serve different sizes to different screens with srcset — the browser picks the smallest file that looks sharp:
<img src="photo-800.jpg" alt="…" srcset="photo-400.jpg 400w, photo-800.jpg 800w, photo-1200.jpg 1200w" sizes="(max-width: 600px) 100vw, 50vw">
Need a different crop on mobile (art direction)? Use <picture>:
<picture> <source media="(max-width: 600px)" srcset="square.jpg"> <img src="wide.jpg" alt="…"> fallback / desktop </picture>
↑ max-width:100% — drag your window narrower and this image scales down instead of overflowing.
Fitting an image into a box: object-fit
When you give an image a fixed width and height, object-fit decides how it fills that box. Same photo, same box, three behaviors:
/* same width & height; object-fit decides how the photo fills it */ .frame img { width: 100%; height: 100%; } .cover img { object-fit: cover; } fills box, crops edges .contain img { object-fit: contain; } fits inside, may letterbox .fill img { object-fit: fill; } stretches, distorts
cover is the workhorse — it's how you get uniform thumbnails and hero images from photos of any shape, without squishing them. Avoid fill; it distorts people and products.<img> vs CSS background image
Two ways to put an image on a page — and they're for different jobs.
The image is content —
a photo, a product, a chart.
It needs alt text and should
appear if CSS fails.
<img src="product.jpg"
alt="Blue running shoe">The image is decoration —
a hero backdrop, a texture,
a pattern behind text.
.hero {
background-image: url(bg.jpg);
background-size: cover;
}<img>. If it's just visual atmosphere → CSS background.Captions: <figure> & <figcaption>
When an image needs a visible caption or credit, wrap it semantically so the caption is programmatically tied to the image.
<figure> <img src="ridge.jpg" alt="A misty mountain range at dawn"> <figcaption>Dawn over the ridge.</figcaption> </figure>
alt describes the image for people who can't see it; the <figcaption> is a visible note for everyone. They serve different jobs — don't just duplicate one into the other.Common mistakes
<img src="DSC_4821.JPG"> no alt, 5MB <img src="logo.jpg"> logo as JPG (blurry) <img ... > with no width/height page jumps object-fit: fill squished people a 3000px image in a 300px box wasted bytes
<img src="team.webp" alt="Our team"
width="600" height="400" loading="lazy">
<img src="logo.svg" alt="Acme"> crisp vector
object-fit: cover clean thumbnails
resize + compress before uploadImage checklist
- Every
<img>has meaningfulalt(oralt=""if purely decorative) - Right format: photo → WebP/JPG, logo/icon → SVG, transparency → PNG/WebP
- Resized to display size and compressed before upload
-
widthandheightset so the layout doesn't jump -
max-width: 100%; height: auto;so it never overflows on mobile -
loading="lazy"on below-the-fold images -
object-fit: coverfor uniform thumbnails; neverfill - Decorative backdrops are CSS backgrounds; content images are
<img>