HTML Guides for img
Learn how to identify and fix common HTML validation errors flagged by the W3C Validator — so your pages are standards-compliant and render correctly across every browser. Also check our Accessibility Guides.
Every <img> element must include at least a src or a srcset attribute to be valid HTML.
The <img> element exists to embed an image into the document, and it needs to know where that image is. The src attribute provides a single URL for the image, while srcset lets you offer multiple image sources for different screen sizes or resolutions.
You might run into this error when using JavaScript to set the image source dynamically, or when using lazy-loading libraries that store the URL in a data- attribute like data-src. While those techniques work at runtime, they produce invalid HTML because the validator still expects src or srcset to be present in the markup.
If you genuinely don't have a source yet, you can use a placeholder or a transparent pixel as the src value.
Invalid Example
<img alt="A cute cat" loading="lazy" data-src="cat.jpg">
Valid Examples
Using src:
<img src="cat.jpg" alt="A cute cat">
Using srcset:
<img srcset="cat-400.jpg 400w, cat-800.jpg 800w"
sizes="(max-width: 600px) 400px, 800px"
alt="A cute cat">
Using both src and a lazy-loading data-src (keeps the markup valid while still supporting lazy loading):
<img src="placeholder.jpg" data-src="cat.jpg" alt="A cute cat">
The HTML specification mandates src on the <img> element because an image without a source has nothing to render. Omitting it produces invalid markup and unpredictable browser behavior — some browsers display a broken image icon, while others render nothing at all.
This issue commonly occurs in a few scenarios:
- Templating placeholders — A developer adds an
<img>tag intending to populate thesrcdynamically but forgets to set a default value. - Lazy loading implementations — Some lazy-loading scripts store the real URL in a
data-srcattribute and omitsrcentirely, which results in invalid HTML. - Incomplete markup — The attribute is simply forgotten during development.
How to fix it
- Add a
srcattribute with a valid URL pointing to your image. - If you're using lazy loading and want to defer the actual image source, set
srcto a lightweight placeholder (such as a tiny transparent image or a low-quality preview) and use the nativeloading="lazy"attribute instead of removingsrc.
Examples
❌ Missing src attribute
<img alt="A sunset over the ocean">
This triggers the validation error because src is absent.
❌ Source stored only in a data- attribute
<img data-src="/images/photo.jpg" alt="A sunset over the ocean">
While data-src is a valid custom data attribute, it does not satisfy the requirement for src. The validator will still report the error.
✅ Correct usage with src
<img src="/images/photo.jpg" alt="A sunset over the ocean">
✅ Lazy loading with a placeholder src
<img
src="/images/photo-placeholder.jpg"
data-src="/images/photo-full.jpg"
alt="A sunset over the ocean"
loading="lazy">
Here, src points to a small placeholder image so the markup stays valid, while data-src holds the full-resolution URL for your lazy-loading script to swap in.
✅ Native lazy loading (no JavaScript needed)
<img src="/images/photo.jpg" alt="A sunset over the ocean" loading="lazy">
Modern browsers support the loading="lazy" attribute natively, so you can keep a valid src and still defer off-screen images without any custom scripting.
The <picture> element is a container that lets you provide multiple image sources for different viewport sizes, resolutions, or format support. It works together with zero or more <source> elements and exactly one <img> element. The browser evaluates each <source> in order, selects the best match based on its media, type, or srcset attributes, and then displays the chosen image in the space occupied by the <img> element. If no <source> matches—or if the browser doesn't support the <picture> element at all—the <img> element's src attribute is used as the final fallback.
The <img> element isn't optional; it's structurally required by the HTML specification. Without it, the <picture> element is incomplete and invalid. This matters for several reasons:
- Rendering: Browsers rely on the
<img>element to actually display the image. A<picture>element with only<source>children will render nothing in most browsers. - Accessibility: The
<img>element carries thealtattribute, which provides a text alternative for screen readers and other assistive technologies. Without it, there's no accessible description of the image. - Fallback support: Older browsers that don't understand
<picture>or<source>will ignore those elements entirely and fall back to the<img>. Without it, those users see nothing. - Standards compliance: The WHATWG HTML specification explicitly states that the
<picture>element's content model requires one<img>element, optionally preceded by<source>elements and inter-element whitespace.
The <img> element should always be the last child inside <picture>, placed after all <source> elements.
Examples
Invalid: <picture> without an <img> element
This markup triggers the validation error because the required <img> child is missing:
<picture>
<source srcset="hero-large.webp" type="image/webp">
<source srcset="hero-large.jpg" type="image/jpeg">
</picture>
Fixed: Adding the required <img> element
Add an <img> as the last child with a src pointing to the default image and a descriptive alt attribute:
<picture>
<source srcset="hero-large.webp" type="image/webp">
<source srcset="hero-large.jpg" type="image/jpeg">
<img src="hero-large.jpg" alt="A panoramic view of the mountain landscape">
</picture>
Using <picture> for responsive images with media queries
When serving different image sizes based on viewport width, the <img> element provides the default (typically the smallest) image:
<picture>
<source srcset="banner-wide.jpg" media="(min-width: 1200px)">
<source srcset="banner-medium.jpg" media="(min-width: 600px)">
<img src="banner-small.jpg" alt="Promotional banner for summer sale">
</picture>
The browser checks each <source> in order. If the viewport is 1200 pixels or wider, banner-wide.jpg is used. If it's between 600 and 1199 pixels, banner-medium.jpg is used. Otherwise, the <img> element's src value of banner-small.jpg is displayed.
Using <picture> for format selection
You can also use <picture> to offer modern image formats with a fallback for browsers that don't support them:
<picture>
<source srcset="photo.avif" type="image/avif">
<source srcset="photo.webp" type="image/webp">
<img src="photo.jpg" alt="Close-up of a sunflower in bloom">
</picture>
Browsers that support AVIF will use the first source, those that support WebP will use the second, and all others will fall back to the JPEG specified in the <img> element. In every case, the <img> element is what makes the <picture> element valid and functional.
When the HTML parser encounters an <svg> or <math> tag, it switches from the HTML namespace into a foreign namespace (SVG or MathML, respectively). Inside these foreign contexts, only elements defined by those specifications are valid. The HTML <img> element does not exist in the SVG or MathML namespaces, so placing it there causes a parsing conflict and triggers the W3C validator error: "HTML start tag img in a foreign namespace context."
This matters for several reasons. Browsers handle this situation inconsistently — some may break out of the foreign namespace to render the <img>, while others may ignore it entirely or produce unexpected layout results. This inconsistency means your page may look correct in one browser but be broken in another. Beyond rendering issues, assistive technologies rely on proper namespace boundaries to interpret content. An <img> in the wrong namespace may lose its accessibility semantics, meaning the alt text could go unannounced to screen reader users.
How to fix it
The fix depends on which foreign namespace context contains the <img>:
Inside <svg>: Replace <img> with the SVG <image> element. Note that SVG's <image> uses the href attribute (not src) and requires x, y, width, and height attributes for positioning and sizing. Unfortunately, SVG's <image> element does not support an alt attribute directly — use a <title> child element or aria-label to provide an accessible name.
Inside <math>: Move the <img> outside the <math> element entirely, or place it inside an <mtext> element. The <mtext> element in MathML is designed to hold text content and, per the HTML parsing rules, can contain embedded HTML elements.
Examples
Incorrect: <img> inside <svg>
<svg width="200" height="200">
<img src="diagram.png" alt="A diagram" width="200" height="200">
</svg>
Correct: using SVG <image> element
<svg width="200" height="200" role="img" aria-label="A diagram">
<image href="diagram.png" x="0" y="0" width="200" height="200" />
</svg>
Correct: with an accessible name via <title>
<svg width="200" height="200" role="img" aria-labelledby="diagram-title">
<title id="diagram-title">A diagram</title>
<image href="diagram.png" x="0" y="0" width="200" height="200" />
</svg>
Incorrect: <img> inside <math>
<math>
<img src="equation.png" alt="x squared plus one">
</math>
Correct: <img> inside <mtext> within <math>
<math>
<mtext>
<img src="equation.png" alt="x squared plus one">
</mtext>
</math>
Correct: <img> moved outside <math>
<img src="equation.png" alt="x squared plus one">
Incorrect: mixed HTML content inside <svg>
<svg width="300" height="150">
<rect width="300" height="150" fill="#eee" />
<img src="icon.png" alt="Icon" width="32" height="32">
<text x="50" y="80">Hello</text>
</svg>
Correct: using <image> alongside other SVG elements
<svg width="300" height="150">
<rect width="300" height="150" fill="#eee" />
<image href="icon.png" x="10" y="10" width="32" height="32" aria-label="Icon" />
<text x="50" y="80">Hello</text>
</svg>
If you need to place HTML content alongside or on top of an SVG, consider using the <foreignObject> SVG element, which explicitly creates an HTML namespace context within SVG:
<svg width="300" height="150">
<rect width="300" height="150" fill="#eee" />
<foreignObject x="10" y="10" width="100" height="100">
<img src="icon.png" alt="Icon" width="32" height="32">
</foreignObject>
</svg>
The <foreignObject> approach is especially useful when you need full HTML capabilities — such as alt text on <img>, form controls, or rich text — inside an SVG graphic.
In earlier versions of HTML, the border attribute on <img> was commonly used to control the border width in pixels. Its most frequent use was border="0" to suppress the default blue border browsers would render around images wrapped in <a> links. While this worked, it mixed presentation with markup — something HTML5 discourages in favor of a clean separation between structure (HTML) and styling (CSS).
The W3C HTML Validator flags this attribute as obsolete because it was removed from the HTML5 specification. Modern browsers still understand it for backward compatibility, but relying on deprecated features is bad practice. It can lead to inconsistencies across browsers, makes your code harder to maintain, and signals to validators and other developers that the markup is outdated.
The recommended approach is to handle image borders entirely in CSS. If you previously used border="0" to remove borders from linked images, most modern CSS resets and normalize stylesheets already handle this. If you're not using a reset, a single CSS rule takes care of it globally — no need to repeat the attribute on every <img> tag.
How to fix it
- Remove the
borderattribute from all<img>elements. - Add a CSS rule to achieve the same effect. For removing borders, use
img { border: 0; }in your stylesheet. For adding a visible border, use properties likeborder: 2px solid #333;.
Examples
❌ Obsolete border attribute
<a href="/products">
<img src="product.jpg" alt="Our product" border="0">
</a>
This triggers the validator warning because border is no longer a valid attribute on <img>.
✅ Fixed with CSS (external/internal stylesheet)
<style>
img {
border: 0;
}
</style>
<a href="/products">
<img src="product.jpg" alt="Our product">
</a>
A single rule in your stylesheet removes borders from all images, which is cleaner and easier to maintain than repeating the attribute on every element.
✅ Fixed with inline CSS (if needed)
<a href="/products">
<img src="product.jpg" alt="Our product" style="border: 0;">
</a>
Inline styles work but aren't ideal for large-scale fixes. Prefer a stylesheet rule when possible.
✅ Adding a decorative border with CSS
If your intent was to add a visible border (e.g., border="2"), replace it with a more flexible CSS equivalent:
<style>
.bordered {
border: 2px solid #333;
}
</style>
<img src="photo.jpg" alt="A scenic landscape" class="bordered">
CSS gives you far more control — you can specify the border style, color, individual sides, and even use border-radius for rounded corners, none of which were possible with the old border attribute.
The border attribute on the <img> element is obsolete in HTML5 and should be replaced with CSS.
Older versions of HTML allowed border as an attribute directly on <img> elements, most commonly set to 0 to remove the blue border that browsers added around images wrapped in links. HTML5 dropped this attribute from the specification. Modern browsers no longer add that default border, so in most cases the attribute can simply be removed.
If you still need to control the border on an image, use CSS instead. You can apply a style directly with the style attribute, use a class, or add a rule in your stylesheet.
HTML examples
Invalid: using the obsolete border attribute
<a href="/home">
<img src="logo.png" alt="Logo" border="0">
</a>
Valid: using CSS instead
<a href="/home">
<img src="logo.png" alt="Logo" style="border: 0;">
</a>
Or, with a stylesheet rule:
<style>
img {
border: 0;
}
</style>
<a href="/home">
<img src="logo.png" alt="Logo">
</a>
The border attribute on the <table> element is obsolete in HTML5 and should be replaced with CSS styling.
The border attribute was commonly used in older HTML to add borders to tables. In HTML5, the only valid value for the border attribute on a <table> is an empty string ("") or "1", and even then it's considered obsolete. The validator message mentions img { border: 0; } because the border attribute was also frequently used on <img> elements, but the same principle applies to tables — presentational attributes should be replaced with CSS.
To style table borders, use the CSS border property on the <table>, <th>, and <td> elements. The border-collapse property is also useful for controlling whether borders are merged or separated.
HTML Examples
❌ Invalid: using the obsolete border attribute
<table border="2">
<tr>
<td>Cell 1</td>
<td>Cell 2</td>
</tr>
</table>
✅ Valid: using CSS for borders
<style>
table, td {
border: 2px solid black;
border-collapse: collapse;
}
</style>
<table>
<tr>
<td>Cell 1</td>
<td>Cell 2</td>
</tr>
</table>
A <button> element shouldn't be placed inside any element that carries role="img", because that role tells assistive technologies to treat the element and everything inside it as a single, flat image.
When you set role="img" on a container, screen readers stop exposing its children as separate, operable controls. The whole subtree collapses into one graphic with a single accessible name. A <button> nested inside disappears from that flattened view: a screen reader user cannot reach or activate it, even though the button still renders and responds to a mouse. The checker flags this because the markup promises an image but hides an interactive control inside it. Current versions of the validator report it as a warning ("should not appear"). Older versions reported it as an error ("must not appear").
This usually happens when role="img" is added to a wrapper that groups an icon or illustration together with a real control, such as a decorative card that also holds a button.
The fix is to decide what the element actually is. If it is an image, keep role="img" and move the button outside it. If it needs a button, remove role="img" from the ancestor and describe any decorative graphics with alt text or aria-label on the image itself.
Invalid example
<div role="img" aria-label="Play the intro video">
<img src="thumbnail.jpg" alt="">
<button type="button">Play</button>
</div>
Valid example
<button type="button" aria-label="Play the intro video">
<img src="thumbnail.jpg" alt="">
</button>
An <img> with a usemap attribute is interactive content, so it can't be placed inside an <a> element.
The usemap attribute connects the image to a <map>, whose <area> elements define clickable regions, each usually with its own href. That makes the image interactive, and the HTML specification doesn't allow interactive content anywhere inside an <a>, whether or not the link has an href. A plain <img> without usemap is fine inside a link, which is why the validator names the attribute.
Wrapping an image map in a link puts links inside a link. A click on a region could follow the region's href or the outer link's, depending on the browser, and screen readers may announce the regions as links nested inside another link.
Decide which behavior the image needs. If the regions matter, move the image out of the <a>, and add a separate link next to it if you still want one to the whole destination. If the image only needs to be a single link, remove the usemap attribute and the unused <map>.
Invalid example
<a href="/regions">
<img src="regions.png" alt="Regions" usemap="#regions" width="200" height="300">
</a>
<map name="regions">
<area shape="rect" coords="0,0,200,150" href="/north" alt="North region">
<area shape="rect" coords="0,150,200,300" href="/south" alt="South region">
</map>
Valid example
<img src="regions.png" alt="Regions" usemap="#regions" width="200" height="300">
<map name="regions">
<area shape="rect" coords="0,0,200,150" href="/north" alt="North region">
<area shape="rect" coords="0,150,200,300" href="/south" alt="South region">
</map>
<p><a href="/regions">View all regions</a></p>
Every HTML element has an implicit ARIA role defined by the HTML specification. The <img> element's implicit role is img, which means assistive technologies like screen readers already recognize it as an image without any additional ARIA attributes. Adding role="img" explicitly doesn't change behavior — it just adds unnecessary noise to your markup and signals that the author may not understand how native semantics work.
The W3C validator flags this because it violates the first rule of ARIA: don't use ARIA if you can use a native HTML element or attribute that already has the semantics you need. Redundant roles clutter your code, make maintenance harder, and can confuse other developers into thinking the role is there for a specific reason.
The role="img" attribute is genuinely useful in other contexts — for example, when you want to group multiple elements together and have them treated as a single image by assistive technologies. A <div> or <span> has no implicit img role, so adding role="img" to a container is meaningful and appropriate.
How to fix it
Simply remove the role="img" attribute from any <img> element. The image semantics are already built in. Make sure you still provide a meaningful alt attribute for accessibility.
Examples
❌ Redundant role on <img>
<img src="photo.jpg" alt="A sunset over the ocean" role="img">
The validator will warn: The "img" role is unnecessary for element "img".
✅ Fixed: Remove the redundant role
<img src="photo.jpg" alt="A sunset over the ocean">
No explicit role is needed. The browser already communicates this element as an image.
✅ Legitimate use of role="img" on a non-image element
The role="img" attribute is appropriate when applied to a container that groups multiple elements into a single conceptual image:
<div role="img" aria-label="Star rating: 4 out of 5">
<span>⭐</span>
<span>⭐</span>
<span>⭐</span>
<span>⭐</span>
<span>☆</span>
</div>
Here, the <div> has no inherent image semantics, so role="img" is meaningful — it tells assistive technologies to treat the entire group as a single image described by the aria-label.
✅ Another legitimate use: CSS background image with role="img"
<div role="img" aria-label="Company logo" class="logo-background"></div>
Since a <div> styled with a CSS background image has no image semantics, role="img" paired with aria-label ensures the visual content is accessible.
The longdesc attribute dates back to HTML4, where it accepted a URL pointing to a separate page (or section of a page) containing a detailed description of the image. The idea was to supplement the short text in the alt attribute with a more comprehensive explanation, particularly useful for complex images like charts, diagrams, or infographics.
HTML5 made longdesc obsolete for several reasons. Browser support was inconsistent — most browsers never exposed the attribute in a way that was easily discoverable by users. Many developers misused it by placing literal descriptions in the attribute instead of URLs, or left it pointing to broken links. Because the attribute was invisible in the rendered page, there was no visual indication that a longer description existed, making it practically useless for sighted users and unreliable for assistive technology users.
The recommended replacements are more robust and accessible:
- Wrap the image in an
aelement (or place a link nearby) that points to the description page. This makes the link visible and usable by everyone. - Use
aria-describedbyto reference a description that already exists on the same page. This is ideal when the detailed description is displayed alongside the image. - Use a
figurewithfigcaptionto associate a visible caption or description directly with the image.
These approaches are better for accessibility because they work reliably across browsers and assistive technologies, and they make the description discoverable to all users, not just those using specific screen readers that happened to support longdesc.
Examples
❌ Obsolete: using longdesc
<img
src="cat.jpg"
alt="Smiling cat sitting on a windowsill"
longdesc="descriptions/smiling-cat.html">
This triggers the validation error because longdesc is no longer a valid attribute on img in HTML5.
✅ Fix: wrap the image in a link
The simplest replacement is to make the image itself a link to the description:
<a href="descriptions/smiling-cat.html">
<img src="cat.jpg" alt="Smiling cat sitting on a windowsill">
</a>
✅ Fix: provide a separate link near the image
If you don't want the image itself to be clickable, place a visible link nearby:
<figure>
<img src="chart.png" alt="Quarterly revenue chart for 2024">
<figcaption>
Quarterly revenue chart.
<a href="descriptions/revenue-chart.html">View detailed description</a>
</figcaption>
</figure>
✅ Fix: use aria-describedby for on-page descriptions
When the long description is already on the same page, reference it with aria-describedby:
<figure>
<img
src="chart.png"
alt="Quarterly revenue chart for 2024"
aria-describedby="chart-description">
<figcaption id="chart-description">
Revenue grew from $2.1M in Q1 to $3.8M in Q4, with the largest
quarter-over-quarter increase occurring between Q2 and Q3.
</figcaption>
</figure>
This approach keeps the description visible on the page and programmatically associates it with the image for screen readers.
Choosing the right approach
| Scenario | Recommended approach |
|---|---|
| Description is on a separate page | Wrap image in an a element or add a nearby link |
| Description is visible on the same page | Use aria-describedby pointing to the description's id |
| Image needs a brief visible caption | Use figure with figcaption |
| Complex image (chart, diagram, infographic) | Combine figure, figcaption, and a link to a full description |
In all cases, make sure the alt attribute still provides a meaningful short description. The long description supplements alt — it doesn't replace it.
The name attribute on the <img> element is obsolete in HTML5 and must be replaced with the id attribute.
Older pages used <img name="logo"> so scripts could reach the image through document.images["logo"], a pattern common in pre-DOM rollover scripts. HTML5 dropped the attribute. An id serves the same purpose: document.getElementById("logo") finds the image, and document.images also indexes images by their id.
The name attribute is still valid on elements like <input>, <form>, <meta>, and <map>, where it has a distinct function. On <img>, though, it has no valid use in modern HTML.
Invalid example
<img src="logo.png" name="logo" alt="Acme logo">
Valid example
<img src="logo.png" id="logo" alt="Acme logo">
Any script that referenced the image as document.images["logo"] keeps working with the id in place, or can switch to document.getElementById("logo").
The name attribute was historically used on img elements to reference images through JavaScript's document.images collection or via document.getElementsByName(). In early HTML, name served as an identifier for various elements before the id attribute was widely adopted. The HTML living standard (WHATWG) now marks name as obsolete on img elements, meaning it should no longer be used in new content.
This matters for several reasons:
- Standards compliance: Using obsolete attributes means your HTML does not conform to the current specification, which can cause validation errors and may lead to unexpected behavior in future browser versions.
- Consistency: The
idattribute is the universal mechanism for uniquely identifying any HTML element. Usingidinstead ofnamekeeps your markup consistent and predictable. - JavaScript and CSS targeting: Modern APIs like
document.getElementById()anddocument.querySelector()work withid, notnameon image elements. CSS selectors also target elements byid(e.g.,#myImage), makingidthe more versatile choice. - Fragment linking: The
idattribute allows you to link directly to an element using a URL fragment (e.g.,page.html#myImage), whereas the obsoletenameattribute onimgdoes not serve this purpose.
To fix this issue, simply replace name with id on your img elements. Keep in mind that id values must be unique within the entire document — no two elements can share the same id. If you have JavaScript code that references the image by name (e.g., document.images["myImage"] or document.getElementsByName("myImage")), update those references to use document.getElementById("myImage") or document.querySelector("#myImage") instead.
Examples
Incorrect: using the obsolete name attribute
<img src="photo.jpg" name="heroImage" alt="A sunset over the ocean">
This triggers the validation error because name is no longer a valid attribute on img.
Correct: using the id attribute
<img src="photo.jpg" id="heroImage" alt="A sunset over the ocean">
The name attribute is replaced with id, and the element can now be targeted with document.getElementById("heroImage") or the CSS selector #heroImage.
Updating JavaScript references
If your existing code references the image by name, update it accordingly.
Before (relying on name):
<img src="logo.png" name="siteLogo" alt="Company logo">
<script>
var logo = document.images["siteLogo"];
logo.style.border = "2px solid blue";
</script>
After (using id):
<img src="logo.png" id="siteLogo" alt="Company logo">
<script>
var logo = document.getElementById("siteLogo");
logo.style.border = "2px solid blue";
</script>
Multiple images that previously shared a name
Since id values must be unique, you cannot give the same id to multiple elements. If you previously used the same name on several images and selected them as a group, switch to a shared class instead:
<img src="slide1.jpg" class="gallery-image" alt="Mountain landscape">
<img src="slide2.jpg" class="gallery-image" alt="Forest trail">
<img src="slide3.jpg" class="gallery-image" alt="River valley">
<script>
var images = document.querySelectorAll(".gallery-image");
images.forEach(function(img) {
img.style.borderRadius = "8px";
});
</script>
This approach is standards-compliant and gives you flexible, modern element selection using class for groups and id for unique elements.
The sizes attribute has a value starting with auto, but the image is not lazy-loaded. A sizes value of auto only works together with loading="lazy".
sizes="auto" tells the browser to pick the srcset candidate that matches the image's actual rendered width, instead of you writing out media conditions by hand. The browser can only know that width after it has laid the image out on the page, which is exactly the point at which a lazy-loaded image is fetched. For an image that loads eagerly, the width is not available in time, so the specification restricts auto to elements that also carry loading="lazy".
To fix the error, add the loading attribute to the same element:
<img
srcset="photo-400.jpg 400w, photo-800.jpg 800w"
sizes="auto"
loading="lazy"
alt="A field of sunflowers">
If the image needs to load eagerly, for example a hero image above the fold, drop auto and give sizes an explicit value instead:
<img
srcset="photo-400.jpg 400w, photo-800.jpg 800w"
sizes="(max-width: 600px) 400px, 800px"
alt="A field of sunflowers">
A sizes value that starts with auto lets the browser work out an image's display size on its own, but the specification only permits it when the same <img> is lazy-loaded with loading="lazy".
The auto keyword removes the need to hand-write media-condition source sizes for a responsive image. For the browser to measure the rendered width and pick a candidate from srcset, the layout around the image has to already exist when the image is fetched. That holds for a lazy-loaded image, which is requested only as it approaches the viewport. An eagerly loaded image can be fetched before its box is laid out, so auto would have nothing to measure, and the validator rejects it.
To fix the error, add loading="lazy" to the same <img>. If the image has to load eagerly, such as a hero image at the top of the page, drop the auto keyword and give sizes explicit lengths instead.
Invalid example
<img
srcset="small.jpg 480w, large.jpg 1024w"
sizes="auto"
src="large.jpg"
alt="Product photo">
Valid example
<img
srcset="small.jpg 480w, large.jpg 1024w"
sizes="auto"
loading="lazy"
src="large.jpg"
alt="Product photo">
Validate at scale.
Ship accessible websites, faster.
Automated HTML & accessibility validation for large sites. Check thousands of pages against WCAG guidelines and W3C standards in minutes, not days.
1K Weekly
1,000 monthly checks. Cancel anytime.
Get 1K Weekly →Join teams across 40+ countries