Skip to main content

no-unpaired-srcset-sizes

Enforces the mutual requirement between srcset width descriptors and the sizes attribute on <img> and <source> elements, per the HTML Living Standard.

Split out of the former srcset-sizes-constraint rule, alongside no-mixed-srcset-descriptors, sizes-auto-requires-lazy-loading, and no-always-matching-source.

#ConstraintTarget
1When sizes is present, srcset must use width descriptors (w) onlyimg, source
2When srcset uses width descriptors, sizes is requiredimg
3Same as 2, unless the following sibling <img> has loading="lazy" (auto-sizes support)source (in <picture>)

How It Works

  • Only <img> and <source> elements inside <picture> are checked.
  • Dynamic attribute values (e.g., Vue :srcset, JSX srcset={...}) and elements with spread attributes are skipped.
  • A descriptor-less image candidate (e.g., image.png without 480w or 2x) does not count as a width descriptor.

❌ Examples of incorrect code for this rule

<!-- sizes + density descriptors -->
<img srcset="a.png 1x, b.png 2x" sizes="100vw" src="a.png" alt="photo" />

<!-- width descriptors without sizes -->
<img srcset="a.png 480w, b.png 1024w" src="b.png" alt="photo" />

<!-- source width descriptors, no sizes, sibling img NOT lazy -->
<picture>
<source srcset="a.webp 480w, b.webp 1024w" />
<img src="a.jpg" alt="photo" />
</picture>

✅ Examples of correct code for this rule

<!-- Width descriptors with sizes -->
<img srcset="a.png 480w, b.png 1024w" sizes="(max-width: 600px) 480px, 1024px" src="b.png" alt="photo" />

<!-- Density descriptors without sizes -->
<img srcset="a.png 1x, b.png 2x" src="a.png" alt="photo" />

<!-- source width descriptors, no sizes, sibling img IS lazy -->
<picture>
<source srcset="a.webp 480w, b.webp 1024w" />
<img src="a.jpg" loading="lazy" alt="photo" />
</picture>

References

Interface

{
"no-unpaired-srcset-sizes": boolean
}

Default Severity

error