HTML Guide for source
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.
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>
Use a valid media length in the sizes attribute; each slot’s length must include a unit (e.g., px, vw) and cannot be unitless.
Detailed explanation
The sizes attribute on responsive images (<img> or <source> within <picture>) specifies, for each media condition, the slot size that the image will occupy in the layout. Each size value must be a valid CSS length with units, or the keyword auto (for <img> only; not useful with <source>). Unitless numbers (e.g., 300) are invalid; use 300px. Percentages are not allowed in sizes. Valid units include: px, em, rem, vw, vh, and the full set listed by the validator (e.g., svw, lvh, cm, etc.).
Common pitfalls:
- Missing units: sizes="(min-width: 768px) 600, 100vw" → 600 must be 600px.
- Using %: sizes="50%" is invalid; use a viewport unit like 50vw.
- Malformed list: values must be comma-separated media conditions followed by a length, ending with a fallback length.
- Putting sizes on <source> is valid, but syntax must match the same rules as on <img>.
Reference keywords:
- sizes
- srcset
- media (on <source>)
- CSS length units
Valid pattern
- With conditions: sizes="(media-condition) length, ... , fallback-length"
- Without conditions: sizes="fallback-length"
HTML examples
Fix missing units
Before (invalid):
<picture>
<source
type="image/webp"
srcset="hero-800.webp 800w, hero-1200.webp 1200w"
sizes="(min-width: 900px) 800, 100vw">
<img
src="hero-800.jpg"
srcset="hero-800.jpg 800w, hero-1200.jpg 1200w"
sizes="(min-width: 900px) 800, 100vw"
alt="Hero image">
</picture>
After (valid):
<picture>
<source
type="image/webp"
srcset="hero-800.webp 800w, hero-1200.webp 1200w"
sizes="(min-width: 900px) 800px, 100vw">
<img
src="hero-800.jpg"
srcset="hero-800.jpg 800w, hero-1200.jpg 1200w"
sizes="(min-width: 900px) 800px, 100vw"
alt="Hero image">
</picture>
Replace percentage with viewport units
Before (invalid):
<picture>
<source
media="(min-width: 600px)"
srcset="card-600.webp 600w, card-900.webp 900w"
sizes="50%">
<img
src="card-600.jpg"
srcset="card-600.jpg 600w, card-900.jpg 900w"
sizes="50%"
alt="Product card">
</picture>
After (valid):
<picture>
<source
media="(min-width: 600px)"
srcset="card-600.webp 600w, card-900.webp 900w"
sizes="50vw">
<img
src="card-600.jpg"
srcset="card-600.jpg 600w, card-900.jpg 900w"
sizes="50vw"
alt="Product card">
</picture>
Clean, minimal example with multiple slots
<picture>
<source
type="image/avif"
srcset="banner-480.avif 480w, banner-960.avif 960w, banner-1440.avif 1440w"
sizes="(min-width: 1200px) 960px, (min-width: 600px) 80vw, 100vw">
<img
src="banner-480.jpg"
srcset="banner-480.jpg 480w, banner-960.jpg 960w, banner-1440.jpg 1440w"
sizes="(min-width: 1200px) 960px, (min-width: 600px) 80vw, 100vw"
alt="Responsive banner">
</picture>
If the validator reports “found Y at Z,” inspect the exact character at position Z for a missing unit, stray %, or malformed comma/whitespace, then replace with a valid CSS length unit.
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.