Guias HTML para source
Aprenda como identificar e corrigir erros comuns de validação HTML sinalizados pelo W3C Validator — para que as suas páginas cumpram os padrões e sejam renderizadas corretamente em todos os navegadores. Consulte também o nosso Guias de acessibilidade.
The <picture> element exists to give browsers a choice between multiple image sources. The browser evaluates each <source> in order, looking for the first one whose conditions match the current environment. These conditions are expressed through the media attribute (e.g., viewport width or resolution) and the type attribute (e.g., image/webp or image/avif). If a <source> lacks both attributes, it acts as an unconditional match — the browser will always select it, making any subsequent <source> elements or an <img> with srcset unreachable. This defeats the purpose of the <picture> element entirely.
The HTML specification requires these attributes specifically to prevent this situation. When a <source> has a following sibling <source> or a following <img> with srcset, at least one selection criterion (media or type) must be present so the browser can meaningfully choose between the options. A <source> without these attributes is only valid if it’s the last <source> before a plain <img> (one without srcset), since in that case it serves as the final fallback within the <picture>.
This matters for several reasons:
- Standards compliance: The HTML living standard explicitly defines this requirement. Violating it produces a validation error.
- Predictable rendering: Without distinguishing attributes, browsers may silently ignore sources or always pick the first one, leading to inconsistent behavior across browsers.
- Performance: The <picture> element is often used to serve smaller images on small viewports or modern formats like WebP and AVIF to browsers that support them. Without proper media or type attributes, these optimizations won’t work as intended.
How to fix it
Add a media attribute, a type attribute, or both to each <source> element that is followed by another <source> or an <img> with srcset:
- Use type when you’re offering the same image in different formats (e.g., AVIF, WebP, JPEG). The browser picks the first format it supports.
- Use media when you’re serving different images based on viewport conditions (art direction). The browser picks the source whose media query matches.
- Use both when you want to combine format negotiation with art direction.
Examples
Incorrect — <source> without media or type
Each <source> below has no selection criterion, so the browser has no way to choose between them:
<picture>
<source srcset="hero.webp">
<source srcset="hero.jpg">
<img src="hero.jpg" srcset="hero-2x.jpg 2x" alt="A mountain landscape">
</picture>
Correct — using type for format negotiation
Adding type lets the browser pick the first format it supports:
<picture>
<source srcset="hero.avif" type="image/avif">
<source srcset="hero.webp" type="image/webp">
<img src="hero.jpg" srcset="hero-2x.jpg 2x" alt="A mountain landscape">
</picture>
Correct — using media for art direction
Adding media lets the browser pick the source that matches the viewport:
<picture>
<source srcset="hero-wide.jpg" media="(min-width: 1024px)">
<source srcset="hero-narrow.jpg" media="(max-width: 1023px)">
<img src="hero-narrow.jpg" srcset="hero-narrow-2x.jpg 2x" alt="A mountain landscape">
</picture>
Correct — combining media and type
You can use both attributes together to serve the right format at the right viewport size:
<picture>
<source srcset="hero-wide.avif" media="(min-width: 1024px)" type="image/avif">
<source srcset="hero-wide.webp" media="(min-width: 1024px)" type="image/webp">
<source srcset="hero-narrow.avif" media="(max-width: 1023px)" type="image/avif">
<source srcset="hero-narrow.webp" media="(max-width: 1023px)" type="image/webp">
<img src="hero-narrow.jpg" alt="A mountain landscape">
</picture>
Correct — single <source> before a plain <img>
When there’s only one <source> and the <img> has no srcset, no media or type is required — but adding type is still recommended for clarity:
<picture>
<source srcset="hero.webp" type="image/webp">
<img src="hero.jpg" alt="A mountain landscape">
</picture>
The sizes attribute tells the browser how wide an image will be displayed at different viewport sizes, so it can choose the best candidate from srcset. It only applies when srcset uses width descriptors (e.g., 480w, 800w). The value is a comma-separated list where:
- Each entry (except the last) is a media condition in parentheses followed by a CSS length — for example, (min-width: 800px) 50vw.
- The final entry is a fallback length with no media condition — for example, 100vw.
The browser evaluates the media conditions from left to right and uses the length from the first one that matches. If none match, it uses the fallback.
The media condition syntax mirrors CSS media queries but without the @media keyword. You can use logical operators like and, or, and not, and features like min-width, max-width, orientation, etc.
Why This Error Occurs
The validator parses the sizes value according to the HTML living standard and CSS Media Queries specification. A parse error is triggered when the value doesn’t conform to the expected grammar. Common causes include:
- Missing parentheses around the media condition: min-width: 600px 50vw instead of (min-width: 600px) 50vw.
- Missing length after a media condition: (min-width: 800px) with no length following it.
- Invalid or missing units on the length: 50 instead of 50vw, 50px, or 50rem.
- Trailing commas or extra separators: (min-width: 600px) 50vw, , 100vw.
- Invalid media feature syntax: typos like (minwidth: 600px) or using unsupported tokens.
- Using sizes with pixel-density descriptors: when srcset uses 1x, 2x instead of width descriptors, the sizes attribute is meaningless and can confuse validators.
Why It Matters
- Browser image selection: Browsers rely on a correctly parsed sizes value to pick the optimal image from srcset. A malformed value causes the browser to fall back to a default size (typically 100vw), which can result in downloading unnecessarily large images on small screens or blurry images on large screens.
- Standards compliance: Invalid sizes values violate the HTML specification and may behave unpredictably across different browsers.
- Performance: Correct sizes values are essential for responsive image optimization. Without them, you lose the bandwidth savings that srcset with width descriptors is designed to provide.
How to Fix It
- Wrap every media condition in parentheses: (min-width: 600px), not min-width: 600px.
- Always include a valid CSS length after each condition: (min-width: 600px) 50vw, not just (min-width: 600px).
- End with a fallback length that has no condition: 100vw.
- Use valid CSS length units: vw, px, em, rem, or calc() expressions.
- Remove trailing or duplicate commas.
- Omit sizes entirely if your srcset uses pixel-density descriptors (1x, 2x).
Examples
Incorrect: missing parentheses around the media condition
<img
src="photo-800.jpg"
srcset="photo-400.jpg 400w, photo-800.jpg 800w"
sizes="min-width: 600px 50vw, 100vw"
alt="A landscape photo">
Correct: parentheses added
<img
src="photo-800.jpg"
srcset="photo-400.jpg 400w, photo-800.jpg 800w"
sizes="(min-width: 600px) 50vw, 100vw"
alt="A landscape photo">
Incorrect: missing length after the media condition
<img
src="banner-800.jpg"
srcset="banner-400.jpg 400w, banner-800.jpg 800w"
sizes="(min-width: 700px), 100vw"
alt="A promotional banner">
The first entry (min-width: 700px) has no length value — the comma makes it look like a separate entry, but it’s incomplete.
Correct: length added after the condition
<img
src="banner-800.jpg"
srcset="banner-400.jpg 400w, banner-800.jpg 800w"
sizes="(min-width: 700px) 60vw, 100vw"
alt="A promotional banner">
Incorrect: using sizes with pixel-density descriptors
<img
src="avatar.jpg"
srcset="avatar@1x.jpg 1x, avatar@2x.jpg 2x"
sizes="(min-width: 600px) 80px, 40px"
alt="User avatar">
The sizes attribute is only meaningful with width descriptors (w). When srcset uses density descriptors (1x, 2x), omit sizes.
Correct: sizes removed for density descriptors
<img
src="avatar.jpg"
srcset="avatar@1x.jpg 1x, avatar@2x.jpg 2x"
alt="User avatar">
Incorrect: trailing comma
<img
src="hero-800.jpg"
srcset="hero-400.jpg 400w, hero-800.jpg 800w"
sizes="(min-width: 800px) 800px, 100vw,"
alt="Hero image">
Correct: trailing comma removed
<img
src="hero-800.jpg"
srcset="hero-400.jpg 400w, hero-800.jpg 800w"
sizes="(min-width: 800px) 800px, 100vw"
alt="Hero image">
Using sizes on a <source> inside <picture>
<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 compound media conditions
You can combine conditions with and:
<img
src="photo-800.jpg"
srcset="photo-400.jpg 400w, photo-800.jpg 800w, photo-1200.jpg 1200w"
sizes="(min-width: 900px) and (orientation: landscape) 50vw, 100vw"
alt="A sample photo">
Full valid document
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Responsive Image Example</title>
</head>
<body>
<img
src="pic-800.jpg"
srcset="pic-400.jpg 400w, pic-800.jpg 800w"
sizes="(min-width: 600px) 50vw, 100vw"
alt="A picture demonstrating valid sizes usage">
</body>
</html>
The sizes attribute tells the browser how wide an image will be displayed at various viewport sizes, so it can choose the best candidate from srcset before the CSS has loaded. Each entry in the sizes list is either a media condition paired with a CSS length, or a bare fallback length at the end. The HTML specification requires these lengths to be valid CSS <length> values, which means a number followed by a recognized unit. The full list of accepted units includes px, em, ex, ch, rem, vw, vh, vmin, vmax, cm, mm, in, pt, pc, and newer viewport units like svw, lvw, dvw, svh, lvh, dvh, and others.
The calc() function is also permitted, which lets you combine units — for example, calc(100vw - 2rem).
Why this matters
The sizes attribute is parsed before layout occurs, meaning the browser relies on it being syntactically correct to make smart download decisions. An invalid value forces the browser to fall back to a default size (typically 100vw), which can lead to downloading images that are far too large or too small. Beyond performance, an invalid sizes value violates the HTML specification, and some browsers may handle the malformed input inconsistently, leading to unpredictable behavior across devices.
Common mistakes
- Missing unit entirely: Writing 800 instead of 800px. Bare numbers without units are not valid CSS lengths (the only exception in CSS is 0, but even 0 should have a unit in sizes for clarity).
- Using percentages: Writing 50% instead of 50vw. Percentages are not allowed in sizes because the browser hasn’t performed layout yet and doesn’t know what the percentage would be relative to. Use viewport units like vw instead.
- Typos or extra characters: A stray character, misplaced comma, or missing whitespace can shift the parser’s position and cause it to find unexpected tokens where it expects a unit.
- Using auto on <source>: The auto keyword for sizes is only valid on <img> elements (and requires the loading="lazy" attribute). Using it on <source> will trigger a validation error.
How to fix it
- Find the position indicated in the error message (“at Z”) to locate the problematic value.
- If the value is a bare number, append the correct unit (e.g., change 600 to 600px).
- If the value uses %, replace it with a viewport-relative unit like vw.
- Ensure commas separate each media-condition/length pair, and that the list ends with a fallback length.
Examples
Adding a missing unit
The value 800 in the sizes attribute is not a valid CSS length because it has no unit.
<!-- ❌ Invalid: "800" is missing a unit -->
<img
src="hero-800.jpg"
srcset="hero-800.jpg 800w, hero-1200.jpg 1200w"
sizes="(min-width: 900px) 800, 100vw"
alt="Hero image">
<!-- ✅ Valid: "800px" has a proper unit -->
<img
src="hero-800.jpg"
srcset="hero-800.jpg 800w, hero-1200.jpg 1200w"
sizes="(min-width: 900px) 800px, 100vw"
alt="Hero image">
Replacing a percentage with a viewport unit
Percentages are not permitted in sizes. Use vw to express a width relative to the viewport.
<!-- ❌ Invalid: "50%" is not an allowed unit in sizes -->
<img
src="card-600.jpg"
srcset="card-600.jpg 600w, card-900.jpg 900w"
sizes="50%"
alt="Product card">
<!-- ✅ Valid: "50vw" means 50% of the viewport width -->
<img
src="card-600.jpg"
srcset="card-600.jpg 600w, card-900.jpg 900w"
sizes="50vw"
alt="Product card">
Fixing the issue on a <source> element
The same rules apply to <source> elements inside <picture>. Every length value needs a valid unit.
<!-- ❌ Invalid: "600" on <source> is missing a unit -->
<picture>
<source
type="image/webp"
srcset="hero-600.webp 600w, hero-1200.webp 1200w"
sizes="(min-width: 768px) 600, 100vw">
<img
src="hero-600.jpg"
srcset="hero-600.jpg 600w, hero-1200.jpg 1200w"
sizes="(min-width: 768px) 600px, 100vw"
alt="Hero image">
</picture>
<!-- ✅ Valid: both <source> and <img> use proper units -->
<picture>
<source
type="image/webp"
srcset="hero-600.webp 600w, hero-1200.webp 1200w"
sizes="(min-width: 768px) 600px, 100vw">
<img
src="hero-600.jpg"
srcset="hero-600.jpg 600w, hero-1200.jpg 1200w"
sizes="(min-width: 768px) 600px, 100vw"
alt="Hero image">
</picture>
Using calc() for mixed-unit sizes
You can use calc() to combine different units, which is especially useful when accounting for padding or margins.
<img
src="article-800.jpg"
srcset="article-800.jpg 800w, article-1200.jpg 1200w"
sizes="(min-width: 1024px) calc(100vw - 4rem), 100vw"
alt="Article image">
Multiple slots with different conditions
A well-formed sizes attribute with several media conditions, ending with a unitless-condition fallback length:
<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>
The general pattern is: sizes="(condition) length, (condition) length, fallback-length". Every length in that list — including the fallback — must be a valid CSS length with a unit or a calc() expression. If the validator error points to a specific character position, inspect that exact spot for a missing unit, a stray %, or malformed whitespace and replace it with one of the recognized units.
The <source> element is used inside <picture>, <audio>, or <video> elements to specify alternative media resources. When used inside a <picture> element, the srcset attribute is required and must contain one or more comma-separated image candidate strings. Each image candidate string consists of a URL and an optional descriptor — either a width descriptor like 400w or a pixel density descriptor like 2x.
This validation error typically occurs when:
- The srcset attribute is present but empty (srcset="").
- The attribute value contains only whitespace.
- The value is malformed or contains syntax errors (e.g., missing URLs, invalid descriptors).
- A dynamic templating system or CMS outputs the attribute with no value.
Why this matters
Browsers rely on the srcset attribute to select the most appropriate image to display based on the user’s device capabilities, viewport size, and network conditions. An empty or invalid srcset means the browser cannot perform this selection, potentially resulting in no image being displayed at all. This degrades the user experience, harms accessibility (screen readers and assistive technologies may encounter unexpected behavior), and violates the HTML specification as defined by the WHATWG living standard.
How to fix it
- Provide at least one valid image URL in the srcset attribute.
- Optionally add descriptors — use width descriptors (w) when combined with the sizes attribute, or pixel density descriptors (x) for fixed-size images.
- If you have no image to provide, remove the <source> element entirely rather than leaving srcset empty.
- Check dynamic output — if a CMS or templating engine generates the srcset value, add a conditional check to omit the <source> element when no images are available.
Examples
❌ Empty srcset attribute
<picture>
<source srcset="" type="image/webp">
<img src="photo.jpg" alt="A sunset over the ocean">
</picture>
This triggers the error because srcset is present but contains no image candidate strings.
❌ Invalid descriptor syntax
<picture>
<source srcset="photo.webp 400" type="image/webp">
<img src="photo.jpg" alt="A sunset over the ocean">
</picture>
This is invalid because 400 is not a recognized descriptor — it must be 400w or a density descriptor like 2x.
✅ Single image candidate
<picture>
<source srcset="photo.webp" type="image/webp">
<img src="photo.jpg" alt="A sunset over the ocean">
</picture>
A single URL without a descriptor is valid and serves as the default 1x candidate.
✅ Multiple candidates with width descriptors
<picture>
<source
srcset="photo-small.webp 400w, photo-medium.webp 800w, photo-large.webp 1200w"
sizes="(max-width: 600px) 400px, (max-width: 1000px) 800px, 1200px"
type="image/webp">
<img src="photo.jpg" alt="A sunset over the ocean">
</picture>
This provides three image candidates with width descriptors, allowing the browser to choose the best match based on the viewport and display density.
✅ Multiple candidates with pixel density descriptors
<picture>
<source srcset="photo.webp 1x, photo-2x.webp 2x" type="image/webp">
<img src="photo.jpg" alt="A sunset over the ocean">
</picture>
Pixel density descriptors tell the browser which image to use based on the device’s pixel ratio — 1x for standard displays and 2x for high-DPI (Retina) screens.
✅ Removing the source element when no image is available
If your application dynamically generates the srcset value and sometimes has no image to provide, omit the <source> element entirely:
<picture>
<img src="photo.jpg" alt="A sunset over the ocean">
</picture>
This is valid because the <img> element inside <picture> serves as the required fallback and can stand alone.
Pronto para validar os seus sites?
Comece o seu teste gratuito hoje.