Image optimization
Start with the bytes and the box
An image can hurt a page before it appears. The browser has to transfer and decode the file, and the layout may move if no space was reserved for it.
WebP supports lossy and lossless compression. AVIF also supports lossy and lossless compression, transparency, animation, HDR, and wide color gamut. MDN reports that AVIF commonly compresses more efficiently than WebP for comparable source sets, but the result depends on the image and encoder settings. Keep a fallback when your supported browser range requires one.
The <picture> element offers formats in order. The browser uses the first <source> whose media condition matches and whose declared type it supports. It uses the child <img> when no <source> qualifies.
<picture>
<source srcset="team.avif" type="image/avif">
<source srcset="team.webp" type="image/webp">
<img src="team.jpg" alt="The engineering team outside the office"
width="1200" height="800">
</picture>
Wrong "Changing .jpg to .avif in the filename converts the bytes."
Right The file must be encoded in the advertised format and served with the appropriate media type. <picture> only selects among resources you provide.
Width and height still belong on responsive images
On an <img>, width and height are intrinsic dimensions in pixels. Modern browsers use them to calculate an aspect ratio before the image loads. CSS can then scale the image while preserving that ratio.
<img src="article.webp" alt="A circuit board under a microscope"
width="1600" height="900" class="article-image">
.article-image {
display: block;
width: 100%;
height: auto;
}
The attributes above do not force a 1600 by 900 CSS-pixel box. They provide the 16:9 ratio used while CSS determines the rendered width. If the attributes describe the wrong ratio, the browser can still adjust after decoding the image, which may cause a shift.
Wrong "Responsive CSS makes width and height attributes obsolete."
Right Responsive CSS controls the displayed size. The attributes give the browser enough information to reserve the displayed image's shape during initial layout.
Lazy-load images that begin offscreen
Native lazy loading is one attribute:
<img loading="lazy" src="gallery-12.webp" alt="A red bicycle"
width="900" height="600">
loading="lazy" tells the browser it may defer an offscreen image until the user scrolls near it. The exact distance is browser behavior. Images expected in the initial viewport, especially a likely Largest Contentful Paint image, should use normal eager behavior.
<img src="hero.webp" alt="New collection"
width="1600" height="900">
loading="eager" is also valid, but it means normal loading. It does not raise the image's fetch priority.
srcset lists candidates; sizes describes the slot
Suppose a card occupies the viewport width on small screens and one third of it on larger screens. Generate several versions with the same crop and aspect ratio, then describe both the files and the layout:
<img
src="shoe-800.webp"
srcset="shoe-400.webp 400w,
shoe-800.webp 800w,
shoe-1200.webp 1200w"
sizes="(max-width: 600px) 100vw, 33vw"
width="1200"
height="800"
alt="White running shoe">
The 400w, 800w, and 1200w descriptors are the files' intrinsic widths. They are not breakpoints. Each value must match the referenced image's real intrinsic width.
The sizes attribute supplies the expected rendered width for each media condition. The browser combines that slot width with the available candidates, display density, and its own selection policy. It may account for bandwidth or user preferences, so application code does not receive a promise that one exact URL will win.
Wrong "At a 600px viewport, the browser chooses the candidate labeled 600w."
Right Candidate selection starts from the matched slot size. A dense display can make an 800px or 1200px resource appropriate for a much narrower CSS slot.
If a width-descriptor srcset has no sizes, its default source size is 100vw. That can overstate a card's slot when the card occupies only one column of a grid.
Do not mix w and x descriptors in one srcset. Density descriptors fit an image whose CSS size is stable:
<img src="avatar.png"
srcset="avatar.png 1x, avatar-2x.png 2x"
width="64" height="64"
alt="Mina Patel">
Resolution switching and art direction solve different problems
Use srcset and sizes when every candidate shows the same composition at a different resolution. Use <picture> with media conditions when the composition changes, such as a close crop on a narrow screen.
<picture>
<source media="(max-width: 599px)" srcset="speaker-close.webp"
width="800" height="1000">
<img src="speaker-stage.webp" alt="Speaker presenting on stage"
width="1600" height="900">
</picture>
The child <img> is required. It supplies the fallback, alternative text, and shared presentation attributes. When art-directed sources have different aspect ratios, put the matching width and height on each <source> so the browser can reserve the selected shape. Format selection can be layered onto responsive candidates by giving each format source its own srcset and sizes, but every extra variant adds encoding and cache cost.
Lazy loading and fetch priority answer separate questions
loading="lazy" controls whether an offscreen request may be deferred. fetchpriority supplies a relative priority preference when the browser fetches the resource. A high priority does not cancel lazy loading.
For a likely hero or LCP image already present in the HTML:
<img src="hero-1200.avif"
srcset="hero-800.avif 800w, hero-1200.avif 1200w, hero-1600.avif 1600w"
sizes="100vw"
width="1600" height="900"
fetchpriority="high"
alt="Spring release dashboard">
For later gallery items:
<img src="gallery-800.webp"
width="1200" height="800"
loading="lazy"
alt="Dashboard filter panel">
Wrong "Mark every image fetchpriority="high" so all images load faster."
Right Priority is relative. MDN recommends using the hint sparingly because incorrect or excessive prioritization can degrade performance. The browser controls its internal priority and how much the hint changes it.
A CDN pipeline needs bounded variants
A useful image pipeline retains an original and derives delivery assets from deterministic parameters: source version, dimensions, crop, format, and quality policy. The application then emits those derived URLs in responsive markup.
Cloudinary documents this pattern directly. Transformation parameters live in the delivery URL. On the first request, the service creates the derived file and delivers it; the CDN caches that derived asset for later requests. Its optional version component can bypass an older cached source after an asset is replaced.
https://res.cloudinary.com/demo/image/upload/c_crop,h_200,w_300/sample.jpg
The exact parameter vocabulary is vendor-specific. The architecture is more important than that URL syntax: a deterministic request should identify one reusable derivative.
Do not expose unlimited width, crop, and quality combinations without controls. Each unique transformation can create more work and another derived asset. A bounded width ladder keeps the responsive set useful without turning arbitrary input into cache fragmentation.
const allowedWidths = [320, 640, 960, 1280] as const;
function imageUrl(id: string, width: (typeof allowedWidths)[number]) {
return `https://images.example.com/${id}/w_${width},fit_cover/photo.webp`;
}
In a real API, validate the requested transformation at the edge or generate URLs from trusted code. The example's host and syntax are illustrative; they are not Cloudinary API syntax.
Wrong "A CDN fixes oversized images because the file is served from a nearby edge."
Right Edge caching reduces repeated delivery distance and origin work. The pipeline must still generate suitable dimensions, encoding, and quality, and the HTML must expose those choices correctly.
Format negotiation changes the cache surface
A pipeline may generate explicit AVIF, WebP, and fallback URLs for <picture>. It may instead use a CDN's documented automatic-format feature. Cloudinary's f_auto, for example, can deliver a supported format chosen for the requesting browser and account setup.
<picture>
<source type="image/avif"
srcset="/img/story-640.avif 640w, /img/story-1280.avif 1280w"
sizes="(max-width: 700px) 100vw, 700px">
<source type="image/webp"
srcset="/img/story-640.webp 640w, /img/story-1280.webp 1280w"
sizes="(max-width: 700px) 100vw, 700px">
<img src="/img/story-1280.jpg" width="1280" height="720"
alt="Train crossing a stone bridge">
</picture>
Explicit URLs make each representation visible in markup and cache keys. Automatic negotiation delegates format selection to the delivery service. Either route needs stable versioning when the source changes. Treat the vendor's documented behavior as the contract rather than assuming every image CDN negotiates or caches variants the same way.
Discovery comes before priority
The parser can discover an <img src> or its responsive candidates in initial HTML. A URL hidden behind client-side JavaScript or a CSS background is discovered later unless another mechanism exposes it. fetchpriority="high" changes the relative priority preference; it does not make an undiscovered resource discoverable.
For a CSS background that measurement identifies as the LCP resource, preload can expose the URL earlier:
<link rel="preload" as="image" href="/img/hero.avif"
type="image/avif" fetchpriority="high">
For a responsive <img>, keep the source selection in HTML and apply the priority hint to the image:
<img src="/img/hero-1280.avif"
srcset="/img/hero-640.avif 640w, /img/hero-1280.avif 1280w"
sizes="100vw"
width="1280" height="720"
fetchpriority="high"
alt="Analytics overview">
Wrong "Preload and fetch priority are interchangeable."
Right Preload starts a fetch for a resource declared in the hint. Fetch priority expresses relative importance, and its effect is browser-dependent. Native lazy loading answers a third question: whether an offscreen image's load may be deferred.
A pipeline review should therefore inspect the generated HTML and the network waterfall. File size alone misses late discovery, incorrect slot hints, layout space, and competition with other critical resources.
dig deeper
Primary sources behind these notes - the specs and official docs worth reading in full.
beta
The interviewer part is in the works.
The diagnostic, personal maps, and AI mock interviews are being finished right now. The notes stay free either way. Leave an email and you'll get the first-cohort invite, plus a month of Pro when it opens.