CSE 134B Web Client Languages
  1. Presentation
  2. Images
  3. HTML
  4. Images in HTML

Presentation · Images 04

Images in HTML

An <img> element looks like the simplest tag in HTML. It is really a negotiation: the author describes the image and lists the files on offer, and the browser, which alone knows the screen, the layout and the network, decides what to fetch and how to draw it.

This page covers the markup side of images: the attributes every image needs, what the browser shows while an image is on its way or after it fails, how to caption one, and the two responsive-image tools HTML gives you, srcset on <img> and the <picture> element. It assumes the pixel arithmetic from What an Image Costs, in particular CSS pixels and device pixels.

1. The parts of <img>

<img> is a void element: it has no content and no closing tag, so everything it knows comes from its attributes. Four of them belong on almost every image.

The parts of an img elementThe tag img src equals lake-800.jpg, alt equals Mount Hood, width equals 800, height equals 533, with a bracket under each attribute. Under src: which file to fetch. Under alt: what the image says, shown when it cannot be. Under width and height together: the shape of the box before the file arrives.<img src="lake-800.jpg" alt="Mount Hood…" width="800" height="533">which file to fetchwhat the image says,shown when it cannot bethe shape of the boxbefore the file arrivesa void element: no content, no closing tag
Four attributes, three jobs. Responsive attributes (srcset, sizes) and loading hints are added to this same tag.
AttributeWhat it doesRule
srcThe URL of the image. With srcset it becomes the fallback candidate.Required
altThe text alternative: what the image says, for anyone or anything that cannot see it.Always present; empty (alt="") only for decoration
width, heightThe image's intrinsic size, as whole numbers of CSS pixels without a unit. The browser takes the aspect ratio from them.On every content image
srcset, sizesOther files the browser may choose instead, and how wide the image will be laid out.When one file cannot suit every screen (sections 4 and 5)
loading, fetchpriority, decodingWhen to fetch and how urgently.Image performance

The missing alt and the empty alt mean different things. An empty value is a statement: this image adds nothing, skip it. A missing attribute is silence, and screen readers fill silence with whatever they can find, often the file name: "lake underscore final underscore 2 dot jpg". Images for people teaches how to write the value; this page only insists that it is always there.

The width and height attributes look like styling, and in the 1990s they were. Today they are data: the size of the file. CSS decides how big the image is drawn. The attributes tell the browser the shape to reserve before it has a single byte of the file, which is the subject of the next section.

<img src="lake-800.jpg" alt="Mount Hood, snow-covered, reflected in a still forest lake." width="800" height="533">

2. Before the image arrives, and when it never does

<img> is a replaced element: an element whose content comes from outside the document and is drawn into a box the layout reserves for it. The browser lays out the box; something else (the image decoder) fills it. <video>, <iframe> and <canvas> are replaced elements too. Two consequences follow. CSS cannot reach inside the picture, so ::before and ::after do nothing on an <img>. And the box exists before its content does, so the browser has to decide how big it is while the file is still on the network.

An image is inline by default, sitting on a line of text like a large letter. That is why an image alone in a block often has a few pixels of space beneath it: the gap left for the descenders of letters that are not there. display: block removes it.

While it loads

The HTML arrives first, the image later, sometimes seconds later. Until the browser knows the image's dimensions, it lays the page out as if the image were zero pixels tall. When the first bytes of the file arrive, the decoder reads the size from the file's header, the box grows, and everything below it is pushed down. A reader who had started reading, or was about to tap a link, sees the page jump. That movement is layout shift, and Google's Cumulative Layout Shift metric (CLS), one of the Core Web Vitals, scores how much of it a page does.

Three states of an image boxThree small page sketches. Left, no width or height: while loading the image box is zero pixels tall and the following text sits directly under the first lines; when the file arrives the text will jump down. Middle, with width and height: a dashed box with a 3 to 2 shape is reserved before the file arrives, so nothing moves when it does. Right, a broken image with alt text: the alt text is drawn in a dashed box in the image's place.No width, height0 tall0 tall until bytes arrive,then the text jumps downWith width, height800 / 533space reserved in advance;nothing moves on arrivalBroken, with altMount Hood, reflectedin a still forest lake.the alt text is drawnwhere the picture would be
Left: no dimensions, so no space until the file arrives. Middle: width and height give the shape in advance. Right: the file failed and the alt text stands in.

The width and height attributes prevent the jump. Browsers map them to the CSS aspect-ratio property, in effect giving every image aspect-ratio: auto 800 / 533 from the attributes. The auto means the real file's ratio wins once it is known; until then the attribute ratio sizes the box. This mapping is Baseline widely available (Chrome and Edge 79, Firefox 71, Safari 15).

The mapping only helps if CSS lets the height follow the width. The attributes also act as a default width and height in pixels, so a fluid image needs one rule to undo the fixed height while keeping the ratio:

@layer base { img { max-inline-size: 100%; block-size: auto; } }

With that rule an 800 by 533 image in a 360-pixel column is drawn 360 wide and 240 tall, and the 240-pixel box is there before the file is. Fluid and responsive images builds on this baseline and measures the shift it prevents.

<!-- The 1990s answer to fluid layouts: no aspect ratio, no reserved space, and a small file stretched up until it blurs. --> <img src="lake.jpg" width="100%" alt="Mount Hood reflected in a lake."> <img src="lake-800.jpg" alt="Mount Hood reflected in a still forest lake." width="800" height="533">

When it never arrives

Images fail: a typo in a path, a server down, a reader who has turned images off to save data, a content blocker, a format the browser cannot decode. A visual browser then draws the alt text where the picture would be, sometimes beside a small broken-image icon, and the exact look differs from browser to browser. With alt="", visual browsers draw nothing at all, which is exactly right for a decoration. With no alt, the reader gets the icon and nothing else.

This is the oldest reason for alt text, and it is still a good test. Turn images off, read the page, and ask whether it still makes sense. If an image's alt text reads as nonsense in the flow of the paragraph, it is probably describing the picture instead of saying what the picture says.

3. <figure> and <figcaption>

A <figure> is self-contained content that the main text refers to and that could move elsewhere (to a margin, an appendix, the next page) without breaking the flow. Its optional <figcaption> is the caption, and it must be the figure's first or last child. A figure is not only for images: code listings, tables, quotations, diagrams and video all qualify, and this site puts every table and diagram in one.

Mount Hood, snow-covered, rising above a dark evergreen forest and reflected in a still lake under a pale lavender sky.
Mount Hood from the shore of a mountain lake. Every technique on this page is in this one figure: three formats, four widths, a sizes that matches this column, and an <img> that carries the alt text and the shape. Photograph: Lake Mountain Landscape, Bonnie Moreland, CC0.
<figure> <img src="lake-800.jpg" alt="Mount Hood, snow-covered, rising above a forest and reflected in a still lake." width="800" height="533"> <figcaption> Mount Hood from the shore of a mountain lake. Photograph: Bonnie Moreland, CC0. </figcaption> </figure>

The caption and the alt text do different jobs, and the difference is worth getting right:

alt<figcaption>
Who reads itPeople and software that cannot see the imageEveryone
What it saysWhat the image says, in its placeWhat the image is about, in addition to it: context, source, credit
When it showsOnly when the image does notAlways
MarkupPlain text in an attributeAny phrasing content: links, emphasis, code

So they should not repeat each other. A screen reader announces the image's alt text and then the caption; if both say "Mount Hood reflected in a lake", the reader hears it twice. Let the alt text describe what is seen, and the caption add what is not: where, when, who took it, why it is here. A credit or a license belongs in the caption, never in the alt text.

The figure also gives its contents a name. In the accessibility tree a <figure> is a figure whose accessible name comes from its caption, so a screen reader that announces figures can say "figure, Mount Hood from the shore of a mountain lake". A loose image followed by a paragraph in italics has no such link.

4. Choosing a resolution: srcset with x descriptors

One file cannot suit every screen. What an Image Costs showed why: an image drawn 400 CSS pixels wide covers 400 device pixels on a DPR 1 screen and 800 on a DPR 2 phone. A 400-pixel file looks soft on the phone; an 800-pixel file is four times the pixels for the desktop reader who cannot see the difference.

The srcset attribute lists the files on offer. Each entry is an image candidate string: a URL, then optionally a descriptor, separated from the next candidate by a comma. The simplest descriptor is the pixel density descriptor, a number followed by x, which says how many image pixels this file has for each CSS pixel of the image's box.

<img src="cat-400.jpg" srcset="cat-400.jpg 1x, cat-800.jpg 2x, cat-1200.jpg 3x" alt="A black-and-white tuxedo cat in profile, looking out of a window." width="400" height="533">
The cat photograph at three densities, as encoded by the site's build script
FileDescriptorPixelsJPEG bytes
cat-400.jpg1x400 × 53322,617
cat-800.jpg2x800 × 106772,417
cat-1200.jpg3x1200 × 1600143,520

The browser compares each descriptor with the screen's DPR and picks a candidate; a DPR 2 phone takes cat-800.jpg, a DPR 1 monitor takes cat-400.jpg and saves 49,800 bytes. A candidate without a descriptor counts as 1x, and if no candidate is 1x, the src file joins the set as the 1x candidate. That makes the srcset above partly redundant (the cat-400.jpg 1x entry could go), but writing it out is clearer.

Density descriptors fit images whose drawn size is fixed in CSS: a 400-pixel product shot in a sidebar, a 48-pixel avatar, a logo. They say nothing about the layout, so sizes has no effect on them. They break down as soon as the image's box changes with the viewport. An image that is 100 percent of a phone's width and a third of a desktop's needs different pixels for different widths, not only densities. That is the next tool.

5. Choosing a size: w descriptors and sizes

A width descriptor is a number followed by w: the width of the file in pixels. Note the unit is w, not px; it describes the file, not the layout. With width descriptors the author states facts about the files and leaves the arithmetic to the browser.

<img src="lake-800.jpg" srcset="lake-480.jpg 480w, lake-800.jpg 800w, lake-1200.jpg 1200w, lake-1600.jpg 1600w" sizes="(min-width: 40rem) 60vw, 100vw" alt="Mount Hood reflected in a still forest lake." width="1600" height="1067">

The browser still needs one more fact: how wide the image will be drawn. It cannot measure, because it chooses the file before layout. The browser's preload scanner reads ahead through the HTML and starts image requests while the style sheets are still downloading, so at the moment it chooses, it does not yet know what the CSS will say. The sizes attribute is the author's promise of what the CSS will do.

sizes is a comma-separated list. Each entry is a media condition followed by a length; the last entry has no condition and is the default. The browser takes the first entry whose condition matches, so order matters, much as in an if/else if chain. The lengths may be any CSS length except a percentage, including vw, rem and calc(); a percentage has nothing to be a percentage of before layout. If sizes is missing, the browser assumes 100vw, which is right for a full-bleed image and wasteful for anything in a column.

How the browser chooses from srcset and sizesThree boxes in a row with arrows between them, then a list of candidates. The viewport is 700 CSS pixels. The sizes condition min-width 40rem matches, so the slot is 60vw, 420 CSS pixels. Times a device pixel ratio of 2 gives 840 pixels needed. Of the candidates, 480w and 800w are too small, 1200w is highlighted as the smallest that covers 840 pixels, and 1600w is larger than needed.viewport700 CSS pxsizes(min-width: 40rem)60vw = 420 px× DPR 2= 840 pxlake-480 480wlake-800 800wlake-1200 1200wlake-1600 1600wsmallest that covers 840the first matching condition wins;the last entry is the defaultthe author states the facts; the browser does the arithmetic and makes the choice
Viewport, sizes, density, candidates. The same markup gives a different answer on every screen.

Internally the browser turns each width descriptor into a density: the file's width divided by the slot width. In the diagram, lake-1200.jpg in a 420-pixel slot is 1200 ÷ 420, about 2.9x; lake-800.jpg is about 1.9x. From there it is the density problem from section 4: find a candidate dense enough for the screen. A DPR 2 screen needs at least 2x, so 1200 it is.

The lake set, as encoded by the site's build script
FileDescriptorJPEG bytesChosen when the slot × DPR is
lake-480.jpg480w13,520up to 480 pixels: a small phone at DPR 1
lake-800.jpg800w33,646481 to 800: a 380-pixel phone at DPR 2
lake-1200.jpg1200w70,458801 to 1200: a 420-pixel slot at DPR 2
lake-1600.jpg1600w119,398above 1200: a wide window at DPR 2 or 3

Rules that trip people up

  • Do not mix descriptor types. The HTML standard requires that if any candidate in a srcset has a width descriptor, they all do. A set of 1x and 800w is invalid, and what a browser does with it is not something to rely on. To combine density thinking with layout, use width descriptors: they already account for density.
  • sizes is ignored with x descriptors. It only means something when there are widths to divide by it.
  • sizes must match the CSS. The browser believes it. Promise 100vw for an image drawn in a 300-pixel card and a DPR 2 phone fetches a file sized for the whole screen; promise too little and the image is soft. The browser never corrects the promise after layout.
  • The choice is the browser's. The standard says the browser picks a candidate "in an implementation-defined manner", and mentions density, zoom and "possibly other factors such as the user's network conditions". A browser may pick a smaller file on a slow connection or when the reader has asked to save data, and current browsers keep using a larger candidate they already have in cache rather than download a smaller one. Write srcset as a menu, not an order.

That last rule surprises everyone the first time. Load a page in a wide window, then narrow it: Chrome keeps the large file it has already decoded, because fetching a smaller one would cost bytes to save nothing. Testing responsive images therefore needs a cold start: DevTools open, Disable cache ticked in the Network panel, the window set to the width under test, then reload.

Writing sizes by hand is the hardest part, because it repeats the layout's arithmetic in a second language. Fluid and responsive images works one example through from a grid layout to the attribute. It also covers sizes="auto", which lets a lazy-loaded image use its real laid-out width, since by the time a lazy image is fetched, layout has happened. It is not Baseline yet: as of October 2026 Chrome and Edge (126) and Firefox (150) support it, Safari does not, so it is written first in a list that falls back to an ordinary sizes value.

6. <picture> and <source>: formats with type

srcset lets the browser choose among sizes of one file. It cannot offer a different format, because nothing in a candidate string says "use this only if you can decode AVIF". A browser that guessed wrong would download a file it could not draw. The <picture> element solves that: it wraps an <img> with any number of <source> elements, each a conditional srcset.

<picture> <source type="image/avif" srcset="lake-800.avif"> <source type="image/webp" srcset="lake-800.webp"> <img src="lake-800.jpg" alt="Mount Hood reflected in a still forest lake." width="800" height="533" loading="lazy"> </picture>

The rules are short, and each one matters:

  1. Order is priority. The browser reads the <source> elements top to bottom and uses the first whose type it supports and whose media condition matches. Later sources are not considered, even if they would suit better. Put the best format first.
  2. type is checked without a download. It is a MIME type the browser compares with its own list of decoders, so an unsupported format costs nothing but a line of HTML.
  3. A <source> uses srcset, not src, and may also carry sizes, media, type, width and height.
  4. The <img> is required and comes last. It is the fallback for browsers that match no source, and more importantly it is the element that is actually drawn. The chosen source only supplies its URL. alt, width, height, loading, decoding and fetchpriority all go on the <img>, and so does all CSS. <picture> itself draws nothing; style the img inside it.
How the browser reads a picture elementFour rows top to bottom: a source with media max-width 36rem and type AVIF, a source with type AVIF, a source with type WebP, and the img. An arrow runs down the left from the first row to the second. Notes on the right: the first source's media is false at this width, so it is skipped; the second source's AVIF type is supported, so its srcset is used; the third is never reached; the img renders the chosen file and supplies alt, width and height.<source media="(max-width: 36rem)" …>1. media is false at this width: skip<source type="image/avif" srcset="…">2. AVIF supported: use this srcset<source type="image/webp" srcset="…">3. never reached<img src="lake-800.jpg" alt="…" …>renders the chosen file, andsupplies alt, width, height, loading
First match wins. The img is always there: it draws whatever the sources chose.

Every <source> can carry its own srcset with width descriptors and its own sizes, so format choice and size choice combine: the browser first picks the source, then picks a candidate inside it. The figure in section 3 does exactly that, and the bytes it saves are real:

One 800 by 533 photograph in the three formats of a typical picture element
FileFormatBytesSupport
lake-800.avifAVIF, quality 5021,823Baseline widely available since July 2026
lake-800.webpWebP, quality 7528,728Baseline widely available
lake-800.jpgJPEG, quality 7533,646Everywhere

With AVIF and WebP both Baseline widely available, every current browser takes the first source, and the WebP and JPEG lines serve only older browsers. That is still worth a few lines of HTML: the fallbacks cost nothing to a browser that never reads them, and they keep the page working for readers on older devices. The same mechanism is how a site can offer a newer format, such as JPEG XL, to the browsers that have it before it is Baseline. Raster formats compares the formats themselves.

The browser's choice is visible from script as img.currentSrc, the URL actually in use, while img.src still reports the fallback in the src attribute. The demo above uses currentSrc to show its choice.

7. Art direction and preferences with media

Everything so far has been resolution switching: the same picture at different sizes or in different formats. The files are interchangeable, and the browser is free to take any of them. Art direction is different. It means showing a different picture, usually a different crop, because the layout calls for it. A wide landscape photograph shrunk onto a phone turns the mountain into a speck; the phone needs a tighter crop that keeps the subject large.

Resolution switchingArt direction
The files areThe same picture, at other sizes or formatsDifferent pictures: crops, compositions, color versions
Markupsrcset and sizes; <source type><source media>
Who decidesThe browser, using hintsThe author, by a rule the browser must follow
If the browser picks "wrong"Harmless: a sharper or smaller copyNot allowed: a matching media is obeyed

A media attribute on <source> holds a media query, and unlike sizes it is a command: if the query matches and the type is supported, the browser uses that source. The art-directed version of the lake photograph uses a square crop on the peak below 36rem and the full scene above it, each in three formats:

<picture> <!-- Narrow screens: the square crop, with its own shape --> <source media="(max-width: 36rem)" type="image/avif" srcset="lake-peak-480.avif 480w, lake-peak-800.avif 800w" sizes="calc(100vw - 2rem)" width="800" height="800"> <source media="(max-width: 36rem)" type="image/webp" srcset="lake-peak-480.webp 480w, lake-peak-800.webp 800w" sizes="calc(100vw - 2rem)" width="800" height="800"> <source media="(max-width: 36rem)" srcset="lake-peak-480.jpg 480w, lake-peak-800.jpg 800w" sizes="calc(100vw - 2rem)" width="800" height="800"> <!-- Everything wider: the whole scene --> <source type="image/avif" srcset="lake-800.avif 800w, lake-1200.avif 1200w, lake-1600.avif 1600w" sizes="(min-width: 48rem) 44rem, calc(100vw - 2rem)"> <source type="image/webp" srcset="lake-800.webp 800w, lake-1200.webp 1200w, lake-1600.webp 1600w" sizes="(min-width: 48rem) 44rem, calc(100vw - 2rem)"> <img src="lake-800.jpg" srcset="lake-800.jpg 800w, lake-1200.jpg 1200w, lake-1600.jpg 1600w" sizes="(min-width: 48rem) 44rem, calc(100vw - 2rem)" alt="Mount Hood, snow-covered, rising above a forest and reflected in a still lake." width="800" height="533"> </picture>

Three details make this work. First, the narrow JPEG needs a <source> of its own: without it, a browser on a narrow screen that supports neither AVIF nor WebP would fall through to the wide <img>. Second, the crops have different shapes, 1:1 and 3:2, so the width and height on the <img> would reserve the wrong box on a phone. Giving each <source> its own width and height fixes that; this is Baseline widely available (since June 2025; Chrome 90, Safari 15, Firefox 108). Third, there is one alt, on the <img>, so it must be true of every crop. Art direction changes the framing, not the meaning: if the narrow crop dropped something the alt text mentions, the crop would be the wrong one.

Use rem in media conditions and in sizes, as the rest of this course does. Inside a media query, em and rem mean the same thing: the browser's default text size, which is 16px unless the reader has changed it. They do not follow the element's font size, the page's own html { font-size }, or the container the image sits in. So 36rem is 576 CSS pixels and 40rem is 640 at the default size, and a reader who has enlarged their text gets the layout, and the crop, meant for that much space. The vw lengths in sizes are measured from the window too; only sizes="auto" sees the real slot, as Fluid and responsive images explains.

Preferences: prefers-color-scheme and others

A media condition is not limited to widths. Any media feature works, including the user preference queries. The commonest is a dark-mode version of an image whose light background would glare in a dark page: a chart, a diagram, a screenshot. Light and dark in the Color section covers which images need a dark version and which, like photographs, do not.

Bar chart of trail visits by month, sample data: about 40 in January, rising to a peak of 98 in July, then falling to 44 in December.
The same chart in two color versions, chosen by prefers-color-scheme: chart.avif is 4,727 bytes and chart-dark.avif 4,604. Switch your system's color scheme and the chart follows.
<picture> <source media="(prefers-color-scheme: dark)" type="image/avif" srcset="chart-dark.avif"> <source media="(prefers-color-scheme: dark)" srcset="chart-dark.png"> <source type="image/avif" srcset="chart.avif"> <img src="chart.png" alt="Bar chart of trail visits by month: …" width="800" height="450" loading="lazy"> </picture>

Order again decides: the dark sources come first, because a dark-scheme browser that supports AVIF matches both the first and the third source, and only the first match counts. Browsers watch the environment for changes and can run the selection again; in current Chromium browsers the swap is immediate when the system color scheme changes. Check your own browser in the demo.

Conditions combine as they do in CSS, with and, so media="(max-width: 36rem) and (prefers-color-scheme: dark)" picks a dark narrow crop. Other preferences are equally available: (prefers-reduced-motion: reduce) can swap an animated image for a still one, which Images for people takes up. Two cautions. A drawing that only needs new colors is better as an SVG that restyles itself, as the logo on What an Image Costs does, than as two raster files. And an image that is pure decoration belongs in CSS, where Images in CSS shows the same switch done with a media query.

8. The source explosion, and letting a build step write the variants

Each technique on this page multiplies the one before. One photograph, offered in three formats at four widths, is twelve files. Add a second crop at two widths and it is eighteen. Add a dark-mode version and it doubles. The markup grows the same way: the art-directed example in section 7 runs to more than twenty lines for one image, and every URL in it must name a file that exists with the width its descriptor claims.

How the variants of one photograph multiply
DecisionVariantsRunning total
One file11
Three formats (AVIF, WebP, JPEG)× 33
Four widths× 412
A second crop at two widths+ 2 × 318
Light and dark versions× 236

Nobody should make thirty-six files by hand, and nobody should type the markup for them either. A hand-made set drifts: someone re-exports one width at a different quality, a file named -800 turns out to be 750 pixels wide, a new photograph gets only a JPEG. The answer in production is to treat the variants as build output, made by a program from one master file each, the same way compiled code is made from source.

This site does exactly that. Every image in this section comes from scripts/images/encode.mjs, a short Node script using the sharp library, which reads the masters in images-src/, writes every format and width into the media folder, and records each file's real width, height and bytes in a manifest.json. The byte counts in this page's tables are read from that manifest; none were typed from memory.

// Responsive sets: each width in each modern format plus a JPEG fallback. for (const [base, file, widths] of [ ['lake', 'lake.jpg', [480, 800, 1200, 1600]], ['cat', 'cat.jpg', [400, 800, 1200]], ]) { for (const w of widths) { for (const ext of ['avif', 'webp', 'jpg']) { job(`${base}-${w}.${ext}`, file, () => photo(file)().resize({ width: w }), ext); } } }

The same idea scales up in several directions. A static site generator can write the <picture> markup from the manifest, so the HTML and the files cannot disagree. A framework's image component does both at once. An image CDN makes variants on request from a URL such as lake.jpg?w=800&format=avif, and caches them. Whatever does the work, the author's job shrinks to the decisions that need a person: which image, which crop, what alt text, and the sizes value that describes the layout.

The other answer to the explosion is restraint. Not every image needs every variant. Four widths is often more than enough, and the gap between them should reflect real savings, not symmetry. A small icon needs no srcset at all if it is an SVG. With AVIF now Baseline, some sites ship AVIF and JPEG only. Image performance takes up the build pipeline, quality settings and an image budget in detail.

9. Summary

ConceptKey points
The parts of <img>A void element. src is the file, alt is the text alternative (empty only for decoration, never missing), width and height are the file's intrinsic size in CSS pixels.
Replaced elements and loadingThe box is laid out before the content arrives. width and height map to aspect-ratio, so with max-inline-size: 100%; block-size: auto the box has the right shape at once and nothing shifts.
Broken imagesVisual browsers draw the alt text in the image's place; with alt="" they draw nothing. Turning images off is a quick test of alt text.
<figure> and <figcaption>Self-contained content the text refers to, with a caption as first or last child. The caption adds context and credit; it does not repeat the alt text.
x descriptorsDensities for an image of fixed size. src counts as 1x. sizes is ignored.
w descriptors and sizesFile widths, plus the author's promise of the drawn width, chosen before layout. First matching condition wins; the default is 100vw. Never mix x and w in one srcset. The browser may pick any candidate, and keeps larger cached ones.
<picture> and typeSources are tried in order; the first with a supported type and matching media wins. The <img> is required, renders the result and carries alt, dimensions and loading attributes. currentSrc shows the choice.
Art direction and mediaResolution switching offers the same picture and lets the browser choose; art direction shows a different picture and the browser must obey. media takes any media query, including prefers-color-scheme. Sources can carry their own width and height for a different shape.
The source explosionFormats × widths × crops × schemes multiply fast. Let a build step make the files and write the markup, as this site's encode.mjs does, and offer only the variants that save real bytes.