Images: img, alt and layout shift
<img src="images/biryani.jpg" alt="A plate of biryani with raita on the side">
One tag, no closing tag, two attributes that both matter. <img> is a void
element — it has no content, so there is nothing to close. <img ... /> with
a trailing slash is legal but pointless; the slash is ignored in HTML.
src is where the file is, and follows every rule in the paths
lesson, including the capital letters that only bite you after
you deploy.
alt is the part people get wrong, and it is the part that matters most.
alt is not a caption and not a description of the file
alt is the replacement for the image. If the image did not exist, what
would you put in its place so the page still made sense?
That framing answers almost every question about it, because the right alt text depends entirely on what the image is doing on the page — not on what is in the picture.
<!-- useless -->
<img src="chart.png" alt="chart">
<img src="chart.png" alt="image of a chart">
<img src="chart.png" alt="chart.png">
<!-- useful -->
<img src="chart.png" alt="Bus ridership doubled between 2019 and 2024">
The first three tell a reader nothing they did not already know. The fourth gives them the information the image was there to convey — which is the whole job.
Two habits to drop straight away. Do not start with "image of" or "picture
of": a screen reader already announces the element as an image, so
alt="image of a dog" is read as "image, image of a dog". And do not paste
the file name, which is what happens by default in a lot of editors and
carries no meaning at all.
The same photograph, three different alt texts
This is the point that makes it click. Take one photo of a busy tea stall:
<!-- in an article about the neighbourhood -->
<img src="stall.jpg" alt="A tea stall on Burns Road with a queue of about twenty people">
<!-- on a page selling the stall's equipment -->
<img src="stall.jpg" alt="A four-burner commercial chai boiler in daily use">
<!-- as the illustration next to a headline that already says all this -->
<img src="stall.jpg" alt="">
Same file, three correct answers. The image has not changed; its purpose has. Ask what the reader would lose if the image vanished, and write that.
Empty alt is a real answer
alt="" means this image is decorative — skip it. A screen reader passes
over it silently, which is exactly right for a background flourish, a divider,
or a photo that only repeats what the adjacent text already says.
This is not the same as leaving alt off entirely:
<img src="swirl.png" alt=""> <!-- correct: deliberately decorative -->
<img src="swirl.png"> <!-- wrong: no information at all -->
With no alt attribute, a screen reader has nothing to work with and typically
falls back to reading out the file name, character by character in the worst
cases. alt="" is a decision. A missing alt is an omission, and every
validator and accessibility checker flags it.
A useful cross-check: if the image is the only thing inside a link, alt=""
leaves that link with no text at all, and the reader hears "link" and nothing
else. An image inside a link must describe the destination, not the picture:
<a href="/"><img src="logo.svg" alt="Chai Corner home"></a>
Not alt="logo". The reader does not need to know it is a logo; they need to
know where the link goes.
Width and height stop the page jumping
You have read this: you start reading a paragraph, an image finishes loading above it, and the text you were looking at is suddenly somewhere else on the screen. On a phone, you often tap the wrong thing at exactly that moment.
That is layout shift, and it happens because the browser did not know how tall the image would be. It lays out the page with a zero-height gap, and when the file arrives it discovers the real dimensions and pushes everything down.
The fix is to tell it in advance:
<img src="biryani.jpg" alt="A plate of biryani with raita" width="800" height="600">
The browser now knows the aspect ratio before a single byte of the image arrives, reserves a correctly-shaped box, and drops the picture into it when it loads. Nothing moves.
Three details that matter:
- These are unitless numbers, not CSS.
width="800", neverwidth="800px". - They must be the image's real pixel dimensions. Getting the ratio wrong distorts the picture or reserves the wrong space, which is the problem you were trying to solve.
- They do not fight responsive CSS. This is the part people assume, and it has not been true for years:
img {
max-width: 100%;
height: auto;
}
With that rule, the image still shrinks to fit its container. Modern browsers
use the width and height attributes purely to compute an aspect ratio,
apply it while loading, and let the CSS take over for the actual size. You get
the reserved space and the responsive behaviour together.
Layout shift is also something Google measures, under Cumulative Layout Shift, and it feeds into search ranking. Two attributes is a cheap fix for a metric that is otherwise fiddly to chase.
loading="lazy", with one exception
<img src="photo-far-down-the-page.jpg" alt="…" width="800" height="600" loading="lazy">
loading="lazy" tells the browser not to fetch the image until the reader is
near it. On a long page of photographs this saves a great deal of data and
makes the first render much faster.
The exception matters: do not lazy-load the image at the top of the page. That one is visible immediately, so deferring it delays the thing the reader is waiting for. It is usually the largest element on screen, which means it is also what Google's Largest Contentful Paint measures. Lazy-loading it makes that number worse, not better.
Rule of thumb: everything below the fold gets loading="lazy"; the hero image
does not.
Picking a format
- SVG for logos, icons and diagrams — vector, so it stays sharp at any size, and usually tiny.
- WebP for photographs. Similar quality to JPEG at roughly a third less weight, and supported everywhere current.
- JPEG for photographs where you need the broadest possible compatibility.
- PNG for images needing sharp edges or transparency. Never for photographs, where it produces enormous files.
The single biggest performance win is not the format, though — it is not
serving a 4000-pixel-wide photograph to a 400-pixel-wide phone. That is what
srcset is for, and it is the next lesson.
A complete tag
<img
src="images/biryani.jpg"
alt="A plate of biryani with raita and a wedge of lemon"
width="1200"
height="800"
loading="lazy">
Source, replacement text, dimensions to hold the space, and deferred loading because it sits well down the page. That is the shape to write from memory.
Next: images on every screen, which turns that one
src into a set the browser chooses from by screen size. If the image is not
appearing at all, it is a path problem — paths covers it.
Prefer learning with a teacher?
WasiLearn Academy runs small-group classes covering this material, online and in Karachi.
See the classes