HTML Guide
A <source>
element inside a <picture>
that is followed by another <source>
or an <img>
with srcset
must include a media
and/or type
attribute.
The <source>
element is used inside <picture>
for responsive images, allowing different resources to be loaded based on conditions such as viewport width (media
) or image format (type
). According to the HTML standard, when multiple <source>
elements are present (or a following <img>
with srcset
), each <source>
must provide a media
and/or type
attribute so the browser can choose the appropriate resource based on those hints.
Without media
or type
, the browser cannot distinguish when to use each source, which can lead to validation errors and unexpected rendering behavior.
Incorrect example (causes the validator error):
<picture>
<source srcset="image1.webp">
<source srcset="image2.jpg">
<img alt="" src="fallback.jpg" srcset="fallback2x.jpg 2x">
</picture>
Correct examples (fixing the error):
<picture>
<source srcset="image1.webp" type="image/webp">
<source srcset="image2.jpg" type="image/jpeg">
<img alt="" src="fallback.jpg" srcset="fallback2x.jpg 2x">
</picture>
or
<picture>
<source srcset="image-small.jpg" media="(max-width: 600px)">
<source srcset="image-large.jpg" media="(min-width: 601px)">
<img alt="" src="fallback.jpg" srcset="fallback2x.jpg 2x">
</picture>
By specifying the media
and/or type
attributes for each <source>
, you satisfy the HTML standard and resolve the W3C validator issue.
Learn more:
Related W3C validator issues
Replace square brackets in srcset URLs or percent-encode them.
The img element’s srcset expects valid URLs for each image candidate. According to the URL Standard, unescaped square brackets are not allowed in the path or query of an HTTP(S) URL used in HTML attributes like srcset. They must be either removed, replaced, or percent-encoded.
- Use safe characters in query parameters (e.g., hyphens or underscores instead of brackets).
- If brackets must remain for backend reasons, percent-encode them: [ -> %5B, ] -> %5D.
- Ensure each image candidate follows the URL [whitespace] descriptor pattern (e.g., 2x, 300w) with commas separating candidates.
HTML examples
Example causing the error
<img
src="image.jpg"
srcset="image.jpg?size=[small] 1x, image@2x.jpg?size=[large] 2x"
alt="Sample">
Corrected example (encode brackets)
<img
src="image.jpg"
srcset="image.jpg?size=%5Bsmall%5D 1x, image@2x.jpg?size=%5Blarge%5D 2x"
alt="Sample">
Corrected example (avoid brackets)
<img
src="image.jpg"
srcset="image.jpg?size=small 1x, image@2x.jpg?size=large 2x"
alt="Sample">
srcset contains candidates without a width descriptor while sizes is present, so each candidate must use a width (w) descriptor.
When an img has sizes, every srcset candidate must include a width descriptor like 320w, not a pixel density descriptor like 1x. Mixed descriptors are not allowed in the same srcset. Use either:
- Width descriptors with sizes (e.g., 320w, 640w, 1024w)
- Density descriptors without sizes (e.g., 1x, 2x)
The browser uses sizes to map CSS layout width to the best w candidate. Without sizes, density (x) can be used, but not together with sizes.
HTML examples
Reproduce the issue (invalid: sizes + x descriptors)
<img
src="photo-640.jpg"
srcset="photo-640.jpg 1x, photo-1280.jpg 2x"
sizes="(max-width: 600px) 100vw, 600px"
alt="Sample photo">
Fix using width descriptors with sizes (valid)
<img
src="photo-640.jpg"
srcset="photo-320.jpg 320w, photo-640.jpg 640w, photo-1280.jpg 1280w"
sizes="(max-width: 600px) 100vw, 600px"
alt="Sample photo">
Alternative fix: remove sizes and use density descriptors (valid)
<img
src="photo-640.jpg"
srcset="photo-640.jpg 1x, photo-1280.jpg 2x"
alt="Sample photo">
sizes contains an invalid media condition; the value must be a comma-separated list of media conditions with corresponding slot sizes, ending with an optional fallback length.
Detailed explanation:
- The sizes attribute on img pairs a media condition with a slot size that represents the layout width of the image for that condition. Syntax: (<media-condition>) <length>[, ...], <length> where the last item can be a bare length fallback.
- A media condition uses the same grammar as CSS media queries. It must be valid CSS, e.g., (min-width: 600px) or (width <= 50rem) and (orientation: landscape). Each condition must be enclosed in parentheses unless using logical operators combining proper conditions.
Common parse errors:
- Missing parentheses: use (min-width: 600px), not min-width: 600px.
- Invalid units or tokens: use px, em, rem, vw, etc.; avoid % in media conditions.
- Missing slot size after a condition: (min-width: 600px) must be followed by a length like 600px.
- Using px only for slot size without units or using percentages: slot size must be a length like 300px, 50vw, not 300.
- Trailing comma or extra commas.
- Misusing comparison syntax: use modern range syntax like (600px <= width <= 1000px) or the traditional form (min-width: 600px) and (max-width: 1000px). Do not write (min-width <= 600px).
- Slot sizes must be lengths: px, em, rem, vw, vh, vmin, vmax, ch. Percentages are not allowed in sizes slot sizes.
- The srcset widths (w descriptors) must correspond to the intrinsic widths of the image candidates, e.g., 400w, 800w. The browser picks one based on sizes.
HTML examples:
-
Correct usage with media conditions and fallback:
<img src="image-800.jpg" srcset="image-400.jpg 400w, image-800.jpg 800w, image-1200.jpg 1200w" sizes="(min-width: 900px) 50vw, (min-width: 600px) 66vw, 100vw" alt="Decorative pattern">
-
Using range syntax and avoiding common mistakes:
<img src="hero-1600.jpg" srcset="hero-800.jpg 800w, hero-1200.jpg 1200w, hero-1600.jpg 1600w" sizes="(800px <= width < 1200px) 80vw, (width >= 1200px) 50vw, 100vw" alt="Hero banner">
-
Minimal fixed example for a typical error (missing parentheses and slot size): Incorrect:
<img src="pic-800.jpg" srcset="pic-400.jpg 400w, pic-800.jpg 800w" sizes="min-width: 600px, 100vw" alt="Sample">
Correct:
<img src="pic-800.jpg" srcset="pic-400.jpg 400w, pic-800.jpg 800w" sizes="(min-width: 600px) 50vw, 100vw" alt="Sample">
-
Example avoiding invalid tokens and commas:
<img src="avatar-256.png" srcset="avatar-128.png 128w, avatar-256.png 256w" sizes="(orientation: landscape) 30vw, 50vw" alt="User avatar">
sizes only accepts a valid media condition list (e.g., (min-width: 600px) 50vw, 100vw); malformed media conditions or missing length values trigger this parse error.
Detailed explanation
- Element: source in a picture or audio/video context. For responsive images, use attributes srcset, optional media, and optional sizes.
-
Attribute: sizes applies only when srcset contains width descriptors (e.g., 320w, 640w). It is a comma-separated list of:
- One or more media conditions followed by a length (e.g., (min-width: 800px) 50vw)
- A final fallback length with no media condition (e.g., 100vw)
Common parse errors:
- Missing parentheses around conditions: min-width: 600px → (min-width: 600px)
- Using invalid units or tokens: 50 (needs a length like 50vw or 50rem)
- Missing length after a condition: (min-width: 800px)
- Trailing commas or malformed separators
- Using sizes while srcset uses pixel density descriptors (1x, 2x); sizes is ignored for x-descriptors and may confuse validators
- Valid media condition syntax mirrors CSS media queries without the @media keyword. Use logical operators and, or, not per CSS Media Queries spec, and ensure spaces and colons are correct.
HTML examples
-
Correct responsive image with width descriptors and sizes
<picture> <source type="image/webp" srcset="hero-480.webp 480w, hero-800.webp 800w, hero-1200.webp 1200w" sizes="(min-width: 1200px) 1200px, (min-width: 800px) 800px, 100vw"> <img src="hero-800.jpg" srcset="hero-480.jpg 480w, hero-800.jpg 800w, hero-1200.jpg 1200w" sizes="(min-width: 1200px) 1200px, (min-width: 800px) 800px, 100vw" alt="Hero image"> </picture>
-
Using viewport width units for simpler sizing
<img src="photo-640.jpg" srcset="photo-320.jpg 320w, photo-640.jpg 640w, photo-1024.jpg 1024w" sizes="(min-width: 900px) 50vw, 100vw" alt="Sample photo">
-
Correct when using pixel density descriptors (omit sizes)
<img src="avatar@1x.jpg" srcset="avatar@1x.jpg 1x, avatar@2x.jpg 2x" alt="User avatar">
Fixing common mistakes
-
Add parentheses and a length:
<img src="img-800.jpg" srcset="img-480.jpg 480w, img-800.jpg 800w" sizes="(min-width: 600px) 50vw, 100vw" alt="Example">
-
Remove stray comma and ensure final fallback:
<img src="banner-800.jpg" srcset="banner-400.jpg 400w, banner-800.jpg 800w" sizes="(min-width: 700px) 60vw, 100vw" alt="Banner">
-
Minimal valid document example
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>Valid sizes Attribute</title> </head> <body> <img src="pic-800.jpg" srcset="pic-400.jpg 400w, pic-800.jpg 800w" sizes="(min-width: 600px) 50vw, 100vw" alt="Picture"> </body> </html>
All values in the srcset attribute must include a width descriptor (such as 300w) when the sizes attribute is present.
The srcset attribute is used to provide multiple image sources for responsive images. Each image candidate string in srcset must specify the image’s width (e.g., 600w) or pixel density (e.g., 2x). When you use a sizes attribute, all srcset candidates must use width descriptors (w).
Example of incorrect usage:
<img
src="/img/pic1.jpg"
srcset="/img/pic1.jpg"
sizes="(max-width: 600px) 100vw, 600px"
alt=""
>
This example is invalid because the srcset value does not include a width descriptor.
Corrected usage with width descriptors:
<img
src="/img/pic1.jpg"
srcset="/img/pic1.jpg 600w"
sizes="(max-width: 600px) 100vw, 600px"
alt=""
>
If you have multiple image sizes, include each with its corresponding width:
<img
src="/img/pic1.jpg"
srcset="
/img/pic1_small.jpg 300w,
/img/pic1.jpg 600w
"
sizes="(max-width: 600px) 100vw, 600px"
alt=""
>
Always match each image URL in srcset with a width (w) or pixel density (x) descriptor if appropriate for your layout.
The srcset property on img elements, when used, requires at least one value. This property is a string which identifies one or more image candidate strings, separated using commas (,) each specifying image resources to use under given circumstances.
Each image candidate string contains an image URL and an optional width or pixel density descriptor that indicates the conditions under which that candidate should be used instead of the image specified by the src property.
Example:
<img
src="/img/cat-200px.png"
alt="Cat"
srcset="
/img/cat-200px.png 1x,
/img/cat-400px.png 2x
">
The srcset attribute requires a width descriptor (w) or pixel density descriptor (x) for each image candidate when the sizes attribute is present.
When using the sizes attribute on an img element, each entry in srcset must include either a width descriptor (e.g., 860w) or a pixel density descriptor (e.g., 2x). This tells browsers how to select the most appropriate image source for the current viewport or display density. Omitting the descriptor leads to HTML validation errors and unexpected image selection.
Correct usage with width descriptors:
<img
alt=""
sizes="(min-width:568px) 140px"
srcset="photo.png?w=860&q=90 860w"
src="photo.png?w=860&q=90">
Correct usage with pixel density descriptors (if sizes is removed):
<img
alt=""
srcset="photo.png?w=860&q=90 2x"
src="photo.png?w=860&q=90">
Key points:
- With sizes, use width descriptors (e.g., 860w).
- Without sizes, you may use pixel density descriptors (e.g., 2x).
- Always use either px or w units in the sizes attribute values; do not use w.
The srcset property on source elements, when used, requires at least one value.
The <source> HTML element specifies multiple media resources for the <picture>, the <audio> element, or the <video> element. It is a void element, meaning that it has no content and does not have a closing tag. It is commonly used to offer the same media content in multiple file formats in order to provide compatibility with a broad range of browsers given their differing support for image file formats and media file formats.
The srcset attribute is required if the source element’s parent is a <picture> element, but not allowed if the source element’s parent is an <audio> or <video> element.
The combination of type="module" and defer is not allowed. The type="module" attribute itself implies that the script should be executed in a deferred way, hence using the defer attribute is unnecessary and invalid.
Steps to Fix the Issue:
- Remove the defer Attribute: When you use type="module", you should not include the defer attribute since module scripts defer automatically.
Incorrect Code:
<script type="module" defer src="example.js"></script>
Corrected Code:
<script type="module" src="example.js"></script>
The <script> tag allows authors to include dynamic scripts and data blocks in their documents. When the src is present, this tag accepts a type attribute which must be either:
- an empty string
- text/javascript (that’s the default, so it can be omitted)
- module
Examples:
<!-- This is valid, without a type it defaults to JavaScript -->
<script src="app.js"></script>
<!-- This is valid, but will warn that it can be omitted -->
<script type="text/javascript" src="app.js"></script>
<!-- An empty attribute is valid, but will warn that it can be omitted -->
<script type="" src="app.js"></script>
<!-- The module keyword is also valid as a type -->
<script type="module" src="app.js"></script>
<!-- Any other type is invalid -->
<script type="wrong" src="app.js"></script>
<script type="text/html" src="app.js"></script>
<script type="image/jpeg" src="app.js"></script>