Lesson 15 / 25
Images
What alternative text should say, how a size declaration affects layout, and how the same image gets served for different screens with a candidate set.
Contents
The document is sectioned, but it still consists of nothing but text. The measurement station page’s location has to get told with an image, and that image has to carry a counterpart for the reader who cannot see it too.
img is an empty element; it has no content, its source gets declared
with the src attribute. Two of its attributes are required: src
and alt.
Alternative Text
The alt attribute carries the text that stands in for the
image. It is not a description of the image; it is the text that does
the image’s job once the image cannot get shown. The test is this: if
I had to translate this image into text, what would I write?
The answer depends on the image’s function in the document, and there are three cases.
An informative image. The alternative text gives that information.
<img src="location.png" alt="The station sits in the middle section of the north-facing slope, 400 meters above the valley floor.">
What gets written here is not how the image looks — colors, drawing style — it is what it says.
A functional image. For an image inside a link or a button, the alternative text stands for the action, not the image.
<a href="/data/2024-03.csv"><img src="download.svg" alt="Download March records"></a>
A decorative image. For an image that adds no information to the document, the alternative text gets left empty.
<img src="divider.svg" alt="">
An empty alt and not writing alt at all are not the same thing.
The empty value is the declaration “this image has no text
counterpart, skip it,” and a screen reader does not announce the
image. If the attribute never gets written, no declaration gets made
at all; many screen readers then read out the file name, which gives
the user nothing.
The words “picture,” “image,” “photo” do not get written into the alternative text; the element’s type already gets announced from its role. The text’s length depends on the content; for descriptions past a few sentences, a separate long-description link gets preferred.
Size Declaration
The width and height attributes declare the image’s intrinsic
dimensions in pixels. This declaration matters even if the
presentation layer shows the image at a different size: the browser
calculates the ratio from it and allots space before the image
downloads.
// ratio.mjs — aspect ratio and allotted height const w = 1440, h = 960; console.log("width/height =", w + "/" + h, "-> ratio", (w / h).toFixed(4)); for (const width of [300, 480, 720]) { console.log(String(width).padStart(4), "pixels wide, height:", (width * h / w).toFixed(1)); }
width/height = 1440/960 -> ratio 1.5000 300 pixels wide, height: 200.0 480 pixels wide, height: 320.0 720 pixels wide, height: 480.0
If the declaration does not get written, the browser allots it zero height until the image downloads; the moment the image downloads, the content below it shifts down. If the user is reading at that moment, or is about to press a button, this shift is a concrete problem. A size declaration prevents this shift and lets layout get calculated without waiting for the download.
The attributes get written without a unit; the writing
width="960px" is invalid.
The loading="lazy" attribute declares that the image does not get
requested until it nears the viewport. It does not get written on
images visible on the first screen — those images are needed right
away, and delaying them slows down the opening.
Candidate Set
A single image file is not suitable for every screen. Sending a wide file to a narrow screen wastes bandwidth; sending a narrow file to a wide, dense screen gives a blurry result.
The srcset attribute declares candidates of the same image at
different widths; sizes declares the image’s width in the
layout. The browser makes the choice.
<img src="slope-960.jpg" srcset="slope-480.jpg 480w, slope-960.jpg 960w, slope-1440.jpg 1440w, slope-1920.jpg 1920w" sizes="(max-width: 600px) 100vw, (max-width: 1000px) 50vw, 640px" width="1440" height="960" alt="The station sits in the middle section of the north-facing slope.">
The selection rule is computable: the first matching condition in the
sizes list gives the source size, each candidate’s density is the
ratio of its w value to the source size, and the smallest-density
candidate meeting the device’s pixel ratio gets chosen.
// candidates.mjs — model of the srcset/sizes candidate selection rule const candidates = [ { src: "slope-480.jpg", w: 480 }, { src: "slope-960.jpg", w: 960 }, { src: "slope-1440.jpg", w: 1440 }, { src: "slope-1920.jpg", w: 1920 }, ]; // "(max-width: 600px) 100vw, (max-width: 1000px) 50vw, 640px" const rules = [ { maxWidth: 600, value: (v) => v * 1.0 }, { maxWidth: 1000, value: (v) => v * 0.5 }, { maxWidth: Infinity, value: () => 640 }, ]; function sourceSize(viewportWidth) { return rules.find((r) => viewportWidth <= r.maxWidth).value(viewportWidth); } function pick(viewportWidth, pixelRatio) { const size = sourceSize(viewportWidth); const densities = candidates.map((c) => ({ ...c, density: c.w / size })); const sufficient = densities.filter((c) => c.density >= pixelRatio); const chosen = sufficient.length > 0 ? sufficient.reduce((min, c) => (c.density < min.density ? c : min)) : densities.reduce((max, c) => (c.density > max.density ? c : max)); return { size, chosen }; } const cases = [[390, 1], [390, 3], [800, 1], [800, 2], [1440, 1], [1440, 2]]; console.log("viewport ratio source size chosen candidate density"); for (const [width, ratio] of cases) { const { size, chosen } = pick(width, ratio); console.log( String(width).padStart(7), String(ratio).padStart(5), String(size).padStart(14), " " + chosen.src.padEnd(15), chosen.density.toFixed(2), ); }
viewport ratio source size chosen candidate density
390 1 390 slope-480.jpg 1.23
390 3 390 slope-1440.jpg 3.69
800 1 400 slope-480.jpg 1.20
800 2 400 slope-960.jpg 2.40
1440 1 640 slope-960.jpg 1.50
1440 2 640 slope-1440.jpg 2.25
The output’s first two lines compare the same screen width at two
different pixel densities: for an image shown at the same size, a
three-times-denser screen gets a three-times-bigger file chosen. The third and fifth lines show that as the screen widens,
the source size changes according to the sizes rule — half the
image at 800 pixels, a fixed 640 pixels at 1440.
Writing sizes incorrectly produces a silent defect: the browser
chooses by the declared size, not the actual size. The declaration
has to stay consistent with the layout.
The choice is the browser’s decision, and it can also weigh network conditions, cached files, or user settings. The calculation above is the rule itself; it is not a guarantee of the result.
Format Selection
The picture element also gets used to choose the candidate set among
different file formats. Its source elements get tried in order,
and the first supported format gets chosen; the img element serves
as both the fallback and the alt-text carrier.
<picture> <source srcset="slope.avif" type="image/avif"> <source srcset="slope.webp" type="image/webp"> <img src="slope.jpg" width="1440" height="960" alt="The station sits in the middle section of the north-facing slope."> </picture>
The same mechanism also shows a different crop on a narrow screen:
when a media condition gets written on the source elements, choice
gets made by screen width. The distinction
between srcset and picture is this — srcset chooses different
scales of the same image, picture chooses different images or
different formats.
Summary
altis not a description of the image, it is the text that stands in for it; in functional images it stands for the action, in decorative images for an empty string.- An empty
altand not writingaltdiffer: the first is the “skip” declaration, the second makes no declaration at all. - A
widthandheightdeclaration gives the aspect ratio and prevents content from shifting by letting space get allotted before the image downloads. srcsetdeclares candidates,sizesdeclares the width in the layout; the choice gets calculated from the source size and the device’s pixel ratio.picturechooses between different formats or different crops;srcsetbetween scales of the same image.
Next Step
The image entered the document, but context is still missing: which measurement point it shows, when it got taken, and which text it belongs to — none of that has been declared. The next lesson takes up the element that associates an image with a caption, and shows how this relationship changes the accessible name.
To keep your progress and take notes, Log in
My notes
Log in to take notes.