In Angular's NgOptimizedImage, how is srcset generated for a fixed-size image versus one with a sizes attribute?
answer
- loader required first
- no sizes: density descriptors
- sizes: width breakpoints
- auto prepended for lazy images
basics
~20 sWith a loader configured, Angular's NgOptimizedImage builds a 1x/2x density srcset from width when there is no sizes attribute, and a width-descriptor srcset from IMAGE_CONFIG breakpoints when sizes is set. ngSrcset or disableOptimizedSrcset override it.
solid answer
~40 sAutomatic `srcset` needs a real loader, because each entry is a loader call with a different width. Without `sizes`, the directive treats the image as fixed-size and emits two density candidates — the loader URL at `width` for `1x` and at twice `width` for `2x` — unless the image is larger than 1920×1080, where it emits none. With `sizes`, it treats the image as responsive and emits one `w` candidate per breakpoint from `IMAGE_CONFIG` (default 16 to 3840 px); for exactly `sizes="100vw"` it keeps only breakpoints of 640 and above. For lazy images it writes `sizes` as `auto, <yours>`, which browsers that support `sizes=auto` use for a more accurate pick. `ngSrcset="400w, 800w"` supplies your own descriptors, and `disableOptimizedSrcset` turns generation off.
code
html · 7 lines<img ngSrc="avatars/ana.jpg" width="96" height="96" alt="Ana" />
<img ngSrc="posts/cover.jpg" width="1200" height="675"
sizes="(max-width: 768px) 100vw, 50vw" alt="Post cover" />
<img ngSrc="posts/diagram.png" width="1600" height="900"
ngSrcset="480w, 960w, 1600w" sizes="80vw" alt="Diagram" />go deeper
Recall that NgOptimizedImage can generate srcset for you once a loader is configured.
Explain density versus width descriptors, when each is generated, and how sizes, breakpoints and ngSrcset change the result.
Audit real srcset output in the DOM, tune IMAGE_CONFIG breakpoints to your layout, and fix missing sizes on responsive images.
Align breakpoints with the image service's cached variants so every generated width is a cache hit.
## Why srcset matters here A `srcset` lists alternative URLs for one image so the browser can download the smallest file that still looks sharp. **`NgOptimizedImage`** builds it for you — but only when it can produce different URLs, which requires an **image loader** (`IMAGE_LOADER` or a built-in loader provider). With the default loader, no `srcset` is generated. ## Fixed-size images: no `sizes` If the image has no `sizes` attribute, the directive assumes it renders at the size given by `width` and `height`. It generates **density descriptors**: ```html <!-- ngSrc="avatars/ana.jpg" width="96" height="96" --> <img srcset="https://img.example.com/avatars/ana.jpg?w=96 1x, https://img.example.com/avatars/ana.jpg?w=192 2x" ...> ``` - Multipliers are **1x and 2x**, calling the loader with `width` and `2 × width`. - If `width` is over **1920** or `height` over **1080** and there is no `sizes`, no srcset is generated; the image is treated as too large for a fixed-size ladder. ## Responsive images: with `sizes` With `sizes`, the directive switches to **width descriptors** based on the breakpoint list in **`IMAGE_CONFIG`**: - Default breakpoints: `16, 32, 48, 64, 96, 128, 256, 384, 640, 750, 828, 1080, 1200, 1920, 2048, 3840`. - One entry per breakpoint: the loader URL at that width, followed by `640w`, `750w` and so on. - When `sizes` is exactly **`100vw`**, breakpoints below **640** are dropped, since a full-viewport image is never that narrow. - `fill` images with no `sizes` get `100vw` by default. Custom breakpoints: ```ts { provide: IMAGE_CONFIG, useValue: { breakpoints: [384, 640, 828, 1200, 1920] } } ``` ## The `auto` prefix For images that end up **`loading="lazy"`**, the directive writes `sizes` as `auto, <your value>` (and `auto, 100vw` for a width-descriptor `ngSrcset` without `sizes`). Browsers that support `sizes="auto"` then use the element's actual laid-out width; others ignore `auto` and use the rest. Priority images keep your `sizes` value as written, because `auto` only applies to lazy images. ## Overriding generation | Want | Use | |---|---| | your own list of widths or densities | `ngSrcset="320w, 640w, 1280w"` or `ngSrcset="1x, 2x, 3x"` | | no srcset for one image | `disableOptimizedSrcset` | | a hand-written `srcset` | not with the directive: combining `srcset` with `ngSrcset` is rejected in development | `ngSrcset` contains only descriptors, never file names; the directive calls the loader for each. Density descriptors are capped: above **3x** is an error, and the directive recommends staying at or below **2x**. ## Writing `sizes` well `sizes` describes the rendered width in CSS terms, such as `(max-width: 768px) 100vw, 50vw` for a one-column/two-column layout. It is the directive's only clue that an image is responsive; leaving it off a full-width image produces a 1x/2x pair at the `width` you gave, which may be much too small or large for the actual screen.
- Why does a 2400x1600 image with no sizes attribute get no srcset?Without `sizes`, the directive would build a fixed-size 1x/2x ladder from `width`. Above 1920 wide or 1080 tall, it skips that because a 2x version of such an image is rarely what a fixed-size slot needs. Add a `sizes` value so it generates width descriptors from the breakpoints instead.
- Why do only lazy images get sizes=auto prepended?`sizes="auto"` lets the browser use the element's laid-out width, which is only known after layout. Lazy images are fetched after layout, so the value is usable; eager images are requested earlier, so the directive keeps the explicit `sizes` you wrote.
saying these in an interview costs you the question
- NgOptimizedImage generates srcset even with the default loader.
- Without sizes, the directive emits the full breakpoint list.
- The directive prepends auto to sizes on every image.
- ngSrcset should list full image URLs.
- 3x and 4x densities are recommended for sharpness.