HTML Guides
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.
The autocomplete attribute tells the browser whether and how it should autofill a form field. The HTML living standard defines a specific set of allowed values — an empty string is not among them. When the attribute is present but empty, the browser receives ambiguous instructions: you’ve explicitly declared the attribute, signaling intent, but provided no actual directive. Different browsers may interpret this inconsistently, some treating it as on, others ignoring it, and others falling back to default behavior.
This matters for several reasons:
- Standards compliance: The WHATWG HTML specification requires autocomplete to contain either the keywords on or off, or one or more valid autofill detail tokens. An empty string satisfies none of these.
- Accessibility: Autofill helps users with motor impairments or cognitive disabilities complete forms more quickly and accurately. An ambiguous autocomplete value can interfere with assistive technologies that rely on these hints.
- User experience: Specific autofill tokens like email, tel, street-address, and current-password allow browsers and password managers to suggest the right data for the right field. Using them correctly makes forms faster and easier to complete.
This issue commonly arises when a framework or template engine outputs autocomplete="" as a default, or when a developer intends to disable autocomplete but leaves the value blank instead of using off.
How to fix it
Choose one of these approaches depending on your intent:
- Remove the attribute if you want default browser behavior (the browser decides whether to autofill).
- Use on to explicitly allow autofill.
- Use off to explicitly discourage autofill (note: browsers may still autofill for login fields regardless).
- Use a specific autofill token to tell the browser exactly what kind of data the field expects. This is the most helpful option for users.
Common autofill tokens include: name, given-name, family-name, email, username, new-password, current-password, tel, street-address, postal-code, country, and cc-number. You can find the full list in the WHATWG autofill specification.
Examples
Incorrect: empty autocomplete value
<input type="text" name="username" autocomplete="">
This triggers the validation error because the attribute is present but contains no valid token.
Correct: remove the attribute entirely
If you have no specific autofill preference, simply omit the attribute:
<input type="text" name="username">
Correct: use on or off
Explicitly enable or disable autofill:
<input type="text" name="username" autocomplete="on">
<input type="text" name="search-query" autocomplete="off">
Correct: use specific autofill tokens
Specific tokens give browsers the best hints for filling in the right data. This is the recommended approach for forms that collect personal information:
<form>
<label for="name">Full name</label>
<input type="text" id="name" name="name" autocomplete="name">
<label for="useremail">Email</label>
<input type="email" id="useremail" name="useremail" autocomplete="email">
<label for="phone">Phone</label>
<input type="tel" id="phone" name="phone" autocomplete="tel">
<label for="pwd">Password</label>
<input type="password" id="pwd" name="pwd" autocomplete="current-password">
<button type="submit">Sign in</button>
</form>
Using precise tokens like current-password and email helps password managers and mobile keyboards provide the most relevant suggestions, improving the experience for all users.
The charset attribute on the <script> element tells the browser what character encoding to use when interpreting the referenced external script file. When a script is written directly inside the HTML document (an inline script), the script’s character encoding is inherently the same as the document’s encoding — there is no separate file to decode. Because of this, the HTML specification requires that charset only appear on <script> elements that also have a src attribute pointing to an external file.
Including charset without src violates the HTML specification and signals a misunderstanding of how character encoding works for inline scripts. Validators flag this because browsers ignore the charset attribute on inline scripts, which means it has no effect and could mislead developers into thinking they’ve set the encoding when they haven’t.
It’s also worth noting that the charset attribute on <script> is deprecated in the HTML living standard, even for external scripts. The modern best practice is to serve external script files with the correct Content-Type HTTP header (e.g., Content-Type: application/javascript; charset=utf-8) or to simply ensure all your files use UTF-8 encoding, which is the default. If you’re working with an older codebase that still uses charset, consider removing it entirely and relying on UTF-8 throughout.
Examples
Incorrect: charset on an inline script
This triggers the validation error because charset is specified without a corresponding src attribute.
<script charset="utf-8">
console.log("Hello, world!");
</script>
Correct: Remove charset from inline scripts
Since inline scripts use the document’s encoding, simply remove the charset attribute.
<script>
console.log("Hello, world!");
</script>
Correct: Use charset with an external script (deprecated but valid)
If you need to specify the encoding of an external script, both charset and src must be present. Note that this usage, while valid, is deprecated.
<script src="app.js" charset="utf-8"></script>
Recommended: External script without charset
The preferred modern approach is to omit charset entirely and ensure the server delivers the file with the correct encoding header, or simply use UTF-8 for everything.
<script src="app.js"></script>
The HTML <figure> element represents self-contained content — such as an image, diagram, code snippet, or quotation — optionally accompanied by a caption provided by a <figcaption> element. When a <figcaption> is present, the browser and assistive technologies already understand the relationship between the figure and its caption. This built-in semantic relationship is part of the ARIA in HTML specification, which governs how native HTML elements map to accessibility roles.
The role attribute is typically used to assign or override the ARIA role of an element for assistive technologies like screen readers. However, the ARIA in HTML specification explicitly restricts certain role assignments when an element’s native semantics are already well-defined by its content. A <figure> with a <figcaption> is one such case — the presence of the caption establishes a clear semantic structure that the role attribute would interfere with.
This restriction exists for several important reasons:
- Accessibility conflicts: Adding role="figure" is redundant since the element already has that implicit role. Adding a different role (like role="img" or role="group") could confuse assistive technologies by contradicting the semantic meaning established by the <figcaption>. Screen readers may ignore the caption or announce the element incorrectly.
- Standards compliance: The ARIA in HTML specification states that when a <figure> has a <figcaption> descendant, no role attribute is allowed. The W3C validator enforces this rule.
- Maintainability: Relying on native HTML semantics rather than ARIA overrides keeps your markup simpler and less error-prone. The first rule of ARIA is: “If you can use a native HTML element with the semantics and behavior you require already built in, do so.”
To fix this issue, remove the role attribute from the <figure> element. The <figcaption> provides all the semantic context needed.
Examples
Incorrect: role attribute on <figure> with <figcaption>
Adding role="figure" is redundant and triggers the validation error:
<figure role="figure">
<img src="chart.png" alt="Sales data for Q3 2024">
<figcaption>Figure 1: Quarterly sales by region.</figcaption>
</figure>
Using a different role like role="img" also triggers the error and can cause accessibility problems:
<figure role="img">
<img src="chart.png" alt="Sales data for Q3 2024">
<figcaption>Figure 1: Quarterly sales by region.</figcaption>
</figure>
Correct: <figure> with <figcaption> and no role
Simply remove the role attribute. The <figure> and <figcaption> elements handle semantics on their own:
<figure>
<img src="chart.png" alt="Sales data for Q3 2024">
<figcaption>Figure 1: Quarterly sales by region.</figcaption>
</figure>
Correct: <figure> without <figcaption> can use a role
If you have a <figure> without a <figcaption>, the restriction does not apply. In this case, you may use a role attribute if needed:
<figure role="img" aria-label="Sales data for Q3 2024">
<img src="chart.png" alt="">
</figure>
Correct: <figure> with <figcaption> containing other media
The fix applies regardless of the type of content inside the <figure>:
<figure>
<pre><code>const greeting = "Hello, world!";</code></pre>
<figcaption>A simple variable assignment in JavaScript.</figcaption>
</figure>
<figure>
<blockquote>
<p>The best way to predict the future is to invent it.</p>
</blockquote>
<figcaption>Alan Kay</figcaption>
</figure>
In every case, the <figcaption> provides the accessible name and descriptive context for the <figure>, making any role attribute unnecessary and non-conformant.
The defer and async boolean attributes control how and when an external script is fetched and executed relative to HTML parsing. These attributes exist specifically to optimize the loading of external resources. An inline <script> block (one without a src attribute) doesn’t need to be “downloaded” — its content is already embedded in the HTML document. Because of this, the defer attribute has no meaningful effect on inline scripts, and the HTML specification explicitly forbids this combination.
According to the WHATWG HTML living standard, the defer attribute “must not be specified if the src attribute is not present.” Browsers will simply ignore the defer attribute on inline scripts, which means the script will execute synchronously as if defer were never added. This can mislead developers into thinking their inline script execution is being deferred when it isn’t, potentially causing subtle timing bugs that are difficult to diagnose.
The same rule applies to the async attribute — it also requires the presence of a src attribute to be valid.
How to fix it
You have two options depending on your situation:
- If the script should be deferred, move the inline code into an external .js file and reference it with the src attribute alongside defer.
- If the script must remain inline, remove the defer attribute entirely. If you need deferred execution for inline code, consider placing the <script> element at the end of the <body>, or use DOMContentLoaded to wait for the document to finish parsing.
Examples
❌ Invalid: defer on an inline script
<script defer>
console.log("hello");
</script>
This triggers the validation error because defer is present without a corresponding src attribute.
✅ Fix option 1: Add a src attribute
Move the JavaScript into an external file (e.g., app.js) and reference it:
<script defer src="app.js"></script>
The browser will download app.js in parallel with HTML parsing and execute it only after the document is fully parsed.
✅ Fix option 2: Remove defer from the inline script
If the script must stay inline, simply remove the defer attribute:
<script>
console.log("hello");
</script>
✅ Fix option 3: Use DOMContentLoaded for deferred inline execution
If you need your inline script to wait until the DOM is ready, wrap the code in a DOMContentLoaded event listener:
<script>
document.addEventListener("DOMContentLoaded", function() {
console.log("DOM is fully parsed");
});
</script>
This achieves a similar effect to defer but is valid for inline scripts.
❌ Invalid: async on an inline script
The same rule applies to async:
<script async>
document.title = "Updated";
</script>
✅ Fixed
<script async src="update-title.js"></script>
Or simply remove async if the script is inline:
<script>
document.title = "Updated";
</script>
When an element has role="button", assistive technologies treat it as a single interactive control — just like a native <button>. Users expect to tab to it once, and then activate it with Enter or Space. If a focusable descendant (an element with tabindex) exists inside that button, it creates a second tab stop within what should be a single control. This breaks the expected interaction model and confuses both keyboard users and screen readers.
The WAI-ARIA specification explicitly states that certain roles, including button, must not contain interactive or focusable descendants. This is because a button is an atomic widget — it represents one action and should receive focus as a single unit. When a screen reader encounters a role="button" element, it announces it as a button and expects the user to interact with it directly. A nested focusable element disrupts this by creating an ambiguous focus target: should the user interact with the outer button or the inner focusable element?
This issue commonly arises when developers wrap inline elements like <span> or <a> with tabindex inside a <div role="button">, often to style parts of the button differently or to add click handlers. The correct approach is to ensure only the outermost button-like element is focusable.
How to fix it
-
Use a native <button> element. This is always the best solution. Native buttons handle focus, keyboard interaction (Enter and Space key activation), and accessibility announcements automatically — no role or tabindex needed.
-
Move tabindex to the role="button" container. If you must use role="button" (for example, when a <div> needs to behave as a button due to design constraints), place tabindex="0" on the container itself and remove tabindex from all descendants.
-
Remove tabindex from descendants. If the inner element doesn’t actually need to be independently focusable, simply remove the tabindex attribute from it.
When using role="button" on a non-interactive element, remember you also need to implement keyboard event handlers for Enter and Space to fully replicate native button behavior.
Examples
Incorrect: focusable descendant inside role="button"
<div role="button">
<span tabindex="0">Click me</span>
</div>
The <span> with tabindex="0" creates a focusable element inside the role="button" container, which violates the ARIA authoring rules.
Incorrect: anchor element inside role="button"
<div role="button" tabindex="0">
<a href="/action" tabindex="0">Perform action</a>
</div>
Even though the container itself is focusable, the nested <a> with tabindex is also focusable, creating two tab stops for what should be a single control.
Correct: use a native <button> element
<button>Click me</button>
A native <button> handles focus, keyboard events, and accessibility semantics out of the box with no additional attributes.
Correct: move tabindex to the role="button" container
<div role="button" tabindex="0">
<span>Click me</span>
</div>
The tabindex="0" is on the role="button" element itself, and the inner <span> is not independently focusable.
Correct: native button with styled inner content
<button>
<span class="icon">★</span>
<span class="label">Favorite</span>
</button>
You can still use inner elements for styling purposes inside a <button> — just don’t add tabindex to them. The button manages focus as a single unit, and screen readers announce the combined text content.
The <meta charset> element tells the browser which character encoding to use when interpreting the bytes of the HTML document. The HTML specification explicitly states that there must be no more than one <meta> element with a charset attribute per document. This declaration should appear within the first 1024 bytes of the document, so placing it as the first child of <head> (right after the opening <head> tag) is the recommended practice.
Duplicate charset declarations typically happen when code is assembled from multiple templates, partials, or snippets — each contributing its own <meta charset>. It can also occur when a developer manually adds a charset declaration without realizing one is already present, or when migrating from an older <meta http-equiv="Content-Type"> approach and adding a new <meta charset> without removing the old equivalent.
Why this matters
- Standards compliance: The WHATWG HTML living standard mandates at most one <meta charset> per document. Violating this produces a validation error.
- Unpredictable behavior: When a browser encounters conflicting or duplicate charset declarations, the behavior is undefined. While most modern browsers will use the first one encountered, relying on this is fragile and could lead to garbled text or encoding issues in edge cases.
- Maintainability: Multiple charset declarations signal disorganized or duplicated template logic, making the codebase harder to maintain.
How to fix it
- Search your HTML document (including any templates, layouts, or partials that compose the final output) for all instances of <meta charset> or <meta charset="...">.
- Keep exactly one <meta charset="utf-8"> declaration, placed as the first element inside <head>.
- Remove all other <meta charset> elements.
- If you also have a legacy <meta http-equiv="Content-Type" content="text/html; charset=utf-8">, remove it — the shorter <meta charset="utf-8"> form is the modern replacement, and having both counts as duplicate charset declarations.
Examples
❌ Incorrect: multiple charset declarations
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta charset="utf-8">
<title>My Page</title>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
The second <meta charset="utf-8"> triggers the validation error, even though both specify the same encoding.
❌ Incorrect: mixing old and new charset syntax
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>My Page</title>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
Both elements declare a character encoding, so the validator treats this as a duplicate.
✅ Correct: single charset declaration
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>My Page</title>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
A single <meta charset="utf-8"> appears first in <head>, before any other elements or content. This is the correct and recommended approach. UTF-8 is the strongly recommended encoding for all new HTML documents.
The HTML parser expects a slash inside a tag to signal the end of a self-closing (void) element, such as <br /> or <img />. When the parser encounters a / that isn’t immediately followed by >, it can’t interpret the tag correctly and raises this error. This can happen in several scenarios:
- A typo in an attribute name or value, such as accidentally typing a / instead of another character.
- An unquoted attribute value that contains a slash, like a URL path.
- A misplaced slash somewhere in the middle of a tag.
While browsers are generally forgiving and may still render the page, relying on error recovery leads to unpredictable behavior across different browsers. Fixing these issues ensures your markup is unambiguous, standards-compliant, and easier to maintain.
Examples
Stray slash in a tag (typo)
A common typo where a slash appears between attributes:
<!-- ❌ Slash not immediately followed by ">" -->
<input type="text" / name="username">
Remove the stray slash:
<!-- ✅ Correct -->
<input type="text" name="username">
Unquoted attribute value containing a slash
If an attribute value contains a / and isn’t wrapped in quotes, the parser sees the slash as part of the tag syntax rather than the value:
<!-- ❌ Unquoted value with slash confuses the parser -->
<img src=images/photo.jpg alt="Photo">
Always quote attribute values, especially those containing slashes:
<!-- ✅ Correct: quoted attribute value -->
<img src="images/photo.jpg" alt="Photo">
Slash in the wrong position for self-closing tags
Placing the slash before the final attribute instead of at the end of the tag:
<!-- ❌ Slash is not immediately before ">" -->
<img src="logo.png" / alt="Logo">
Move the self-closing slash to the very end, or simply remove it (self-closing syntax is optional in HTML5 for void elements):
<!-- ✅ Correct: slash at the end -->
<img src="logo.png" alt="Logo" />
<!-- ✅ Also correct: no self-closing slash needed in HTML -->
<img src="logo.png" alt="Logo">
Accidental double slash
Sometimes a self-closing tag ends up with an extra slash:
<!-- ❌ Double slash before ">" -->
<br //>
Use a single slash or omit it entirely:
<!-- ✅ Correct -->
<br />
<!-- ✅ Also correct -->
<br>
In CSS, a length value is composed of two parts: a number and a unit. Writing just px provides the unit but omits the number, which makes the declaration invalid. The CSS parser cannot interpret px alone as a meaningful measurement, so the property is ignored entirely. This means your intended layout won’t be applied, potentially causing elements to render at unexpected sizes across different browsers.
This error commonly arises from typos, copy-paste mistakes, or templating issues where a variable that should output a number resolves to an empty string, leaving behind only the unit suffix. It can also happen when a numeric value is accidentally deleted during editing.
Beyond layout breakdowns, invalid CSS can cause inconsistent rendering across browsers. Some browsers may silently discard the invalid declaration, while others might apply unexpected fallback behavior. Keeping your CSS valid ensures predictable, cross-browser results and makes your stylesheets easier to maintain and debug.
How to Fix It
- Add the missing numeric value — Pair every unit with a number, e.g., 300px, 1.5em, 50%.
- Use 0 without a unit for zero values — The value 0 is valid on its own and doesn’t require a unit.
- Use a valid keyword — Properties like width accept keywords such as auto, min-content, max-content, and fit-content.
- Check dynamic values — If a preprocessor or template engine generates the value, verify it outputs a complete length (e.g., ${value}px where value is not empty).
Examples
Incorrect: unit without a number
<style>
.box {
width: px;
}
</style>
<div class="box">Content</div>
The declaration width: px is invalid because px alone is not a recognized CSS value. The browser will discard this rule.
Incorrect: number without a unit
<style>
.box {
width: 300;
}
</style>
<div class="box">Content</div>
A unitless number (other than 0) is also invalid for the width property. Browsers will ignore this declaration as well.
Correct: number paired with a unit
<style>
.box {
width: 300px;
}
</style>
<div class="box">Content</div>
Correct: using different valid length units
<style>
.box-a {
width: 50%;
}
.box-b {
width: 20em;
}
.box-c {
width: 15rem;
}
.box-d {
width: 80vw;
}
</style>
Correct: zero value and keywords
<style>
.collapsed {
width: 0;
}
.flexible {
width: auto;
}
.intrinsic {
width: fit-content;
}
</style>
The value 0 is the only number that doesn’t require a unit in CSS. Keywords like auto, min-content, max-content, and fit-content are also valid for width and don’t use numeric lengths at all.
Common CSS Length Units
| Unit | Description |
|---|---|
| px | Pixels (absolute unit) |
| em | Relative to the element’s font size |
| rem | Relative to the root element’s font size |
| % | Percentage of the containing block’s dimension |
| vw | 1% of the viewport width |
| vh | 1% of the viewport height |
| ch | Width of the “0” character in the element’s font |
Always double-check that your CSS length values include both a number and a unit. If you’re generating styles dynamically, add safeguards to ensure the numeric portion is never empty before the unit is appended.
The <label> element represents a caption for a form control. When you use the for attribute, its value must match the id of the form control it labels. According to the HTML specification, an id attribute value must not contain any whitespace characters — this includes spaces, tabs, line feeds, carriage returns, and form feeds. Since for must reference a valid ID, the same restriction applies to its value.
This error typically occurs when a developer uses a space-separated name (like "user name" or "first name") instead of a single continuous token. Browsers may fail to establish the programmatic association between the label and its form control when the for value contains whitespace. This directly impacts accessibility: screen readers rely on this association to announce the label text when a user focuses on the input. It also breaks the click-to-focus behavior where clicking a label moves focus to its associated control.
To fix this issue, replace any whitespace in the for attribute value with a valid character such as a hyphen (-), underscore (_), or camelCase. Make sure the id on the corresponding form control matches exactly.
Examples
Incorrect — whitespace in the for attribute
<form>
<label for="user name">Name</label>
<input type="text" id="user name">
</form>
The value "user name" contains a space, which makes it an invalid ID reference. The validator will report: Bad value “user name” for attribute “for” on element “label”: An ID must not contain whitespace.
Correct — using an underscore instead of a space
<form>
<label for="user_name">Name</label>
<input type="text" id="user_name">
</form>
Correct — using a hyphen instead of a space
<form>
<label for="user-name">Name</label>
<input type="text" id="user-name">
</form>
Correct — using camelCase
<form>
<label for="userName">Name</label>
<input type="text" id="userName">
</form>
Incorrect — leading or trailing whitespace
Whitespace doesn’t have to be in the middle of the value to trigger this error. Leading or trailing spaces also make the ID invalid:
<form>
<label for=" email">Email</label>
<input type="text" id=" email">
</form>
This can be easy to miss when values are generated dynamically or copied from another source. Trim the value to fix it:
<form>
<label for="email">Email</label>
<input type="text" id="email">
</form>
Alternative — wrapping the input inside the label
If you wrap the form control inside the <label> element, you don’t need the for attribute at all. The association is implicit:
<form>
<label>
Name
<input type="text">
</label>
</form>
This approach avoids potential ID mismatches entirely, though explicit for/id pairing is often preferred for flexibility in layout and styling.
The gap property is a shorthand for row-gap and column-gap, used in CSS Grid, Flexbox, and multi-column layouts to define spacing between items or tracks. According to the CSS Box Alignment specification, the accepted values for gap are length values (px, em, rem, %, vh, etc.), the normal keyword, or the calc() function. The keyword auto — while valid for many other CSS properties like margin, width, and grid-template-columns — is simply not part of the gap property’s value grammar.
This confusion often arises because developers are accustomed to using auto for spacing in other contexts. For instance, margin: auto is a common centering technique, and auto is widely used in grid track sizing. However, the gap property serves a different purpose: it defines a fixed or computed gutter size between items, and auto has no defined meaning in that context.
Why this matters
- Standards compliance: Using an invalid value means the browser will ignore the entire gap declaration, falling back to the default value of normal (which is typically 0px in Grid and Flexbox). This can lead to unexpected layout results where items have no spacing at all.
- Cross-browser consistency: While some browsers may be lenient with invalid CSS values, others will strictly discard them. This creates inconsistent layouts across different browsers and versions.
- Maintainability: Invalid CSS values can mask the developer’s intent, making it harder for others (or your future self) to understand what spacing was desired.
How to fix it
Replace auto with a valid value for gap:
- A specific length: gap: 16px;, gap: 1rem;, gap: 0.5em;
- A percentage: gap: 2%;
- The normal keyword: gap: normal; (resolves to 0px in Flexbox and Grid)
- A calc() expression: gap: calc(1rem + 4px);
- Two values for row and column separately: gap: 16px 24px;
If you were using auto because you wanted the browser to determine the spacing dynamically, consider using a percentage value, a viewport-relative unit (vw, vh), or CSS clamp() for responsive gutters.
Examples
Incorrect: using auto as a gap value
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: auto;">
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
<div>Item 4</div>
</div>
This triggers the validation error because auto is not a valid gap value. The browser will discard the declaration entirely.
Correct: using a fixed length
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 16px;">
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
<div>Item 4</div>
</div>
Correct: using separate row and column gaps
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 12px 24px;">
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
<div>Item 4</div>
</div>
Correct: using a percentage for responsive spacing
<div style="display: flex; flex-wrap: wrap; gap: 2%;">
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
</div>
Correct: using clamp() for fluid responsive gaps
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: clamp(8px, 2vw, 32px);">
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
<div>Item 4</div>
</div>
This approach gives you a gap that scales with the viewport width, bounded between 8px and 32px — a useful alternative if you were reaching for auto to get flexible spacing behavior.
The name attribute on <a> elements was historically used to create named anchors — fragment targets that could be linked to with href="#anchorName". In modern HTML (the WHATWG living standard), the name attribute on <a> is considered obsolete for this purpose. The id attribute is now the standard way to create fragment targets, and it can be placed on any element, not just <a> tags.
Regardless of whether you use name or id, the value must be a non-empty string. The W3C validator enforces this rule because an empty identifier serves no functional purpose — it cannot be referenced by a fragment link, it cannot be targeted by JavaScript, and it creates invalid markup. Browsers may silently ignore it, but it pollutes the DOM and signals a likely mistake in the code.
Empty name attributes often appear in content migrated from older CMS platforms or WYSIWYG editors that inserted placeholder anchors like <a name=""></a>. They can also result from templating systems where a variable intended to populate the attribute resolved to an empty string.
Why this matters
- Standards compliance: Both the WHATWG HTML living standard and the W3C HTML specification require that identifier-like attributes (id, name) must not be empty strings.
- Accessibility: Screen readers and assistive technologies may attempt to process named anchors. Empty identifiers create noise without providing any navigational value.
- Functionality: An empty name or id cannot be used as a fragment target, so the element is effectively useless as a link destination.
How to fix it
- Remove the element entirely if the empty anchor serves no purpose — this is the most common fix.
- Replace name with id and provide a meaningful, non-empty value if you need a fragment target.
- Move the id to a nearby semantic element instead of using a standalone empty <a> tag. For example, place the id directly on a heading, section, or paragraph.
- Ensure uniqueness — every id value in a document must be unique.
Examples
❌ Empty name attribute triggers the error
<a name=""></a>
<h2>Introduction</h2>
<p>Welcome to the guide.</p>
❌ Empty name generated by a template
<a name=""></a>
<p>This anchor was meant to be a target but the value is missing.</p>
<a href="#">Jump to section</a>
✅ Remove the empty anchor if it’s unnecessary
<h2>Introduction</h2>
<p>Welcome to the guide.</p>
✅ Use id on the target element directly
<h2 id="introduction">Introduction</h2>
<p>Welcome to the guide.</p>
<!-- Link to the section from elsewhere -->
<a href="#introduction">Go to Introduction</a>
✅ Use id on a standalone anchor if needed
If you need a precise anchor point that doesn’t correspond to an existing element, use an <a> tag with a valid, non-empty id:
<a id="section-start"></a>
<p>This paragraph follows the anchor point.</p>
<a href="#section-start">Jump to section start</a>
✅ Migrate legacy name to id
If your existing code uses the obsolete name attribute with a valid value, update it to use id instead:
<!-- Before (obsolete but was valid in HTML4) -->
<a name="contact"></a>
<!-- After (modern HTML) -->
<a id="contact"></a>
<!-- Even better: put the id on a semantic element -->
<h2 id="contact">Contact Us</h2>
In CSS, property values such as lengths, percentages, and keywords are written without quotation marks. Quotes in CSS are reserved for specific contexts like content property strings, font family names with spaces, and url() paths. When you wrap a margin value (or any similar CSS property value) in double or single quotes, the CSS parser interprets it as a string literal rather than a set of length or keyword values. Since "0 0 1em 0" is a string and not a valid margin value, the declaration is ignored by browsers and flagged by the W3C validator.
This is a problem for several reasons. First, the style will silently fail — browsers discard CSS declarations they can’t parse, so your intended margins won’t be applied, potentially breaking your layout. Second, it indicates a misunderstanding of CSS syntax that could lead to similar errors in other properties. This mistake commonly occurs when developers confuse HTML attribute quoting rules with CSS value syntax, especially when writing inline style attributes where the attribute value itself is already quoted.
The margin property accepts one to four values, each of which can be a length (e.g., 10px, 1em), a percentage, auto, or a global keyword like inherit. None of these require quotes. The fix is straightforward: remove the quotation marks around the CSS value.
Examples
❌ Incorrect: margin value wrapped in quotes
In a <style> block:
<style>
.card {
margin: "0 0 1em 0";
}
</style>
In an inline style:
<p style="margin: '10px auto'">Hello</p>
Both of these produce the validator error because the CSS parser sees a quoted string instead of valid margin values.
✅ Correct: margin value without quotes
In a <style> block:
<style>
.card {
margin: 0 0 1em 0;
}
</style>
In an inline style:
<p style="margin: 10px auto">Hello</p>
Valid margin value formats
For reference, here are the accepted patterns for the margin property — none of which use quotes:
/* All four sides */
margin: 1em;
/* Vertical | Horizontal */
margin: 5% auto;
/* Top | Horizontal | Bottom */
margin: 1em auto 2em;
/* Top | Right | Bottom | Left */
margin: 2px 1em 0 auto;
/* Global keywords */
margin: inherit;
margin: initial;
margin: unset;
Watch out for inline style quoting confusion
A common source of this mistake is confusion about the quotes used for the HTML style attribute versus the CSS values inside it. The outer quotes delimit the attribute value for HTML — the CSS inside should not have its own quotes around property values:
<!-- ❌ Wrong: extra quotes around the CSS value -->
<div style="margin: '1em'"></div>
<!-- ✅ Correct: only the HTML attribute is quoted -->
<div style="margin: 1em"></div>
This same rule applies to other CSS properties like padding, border, font-size, color, and so on. If you see a similar validator error for any CSS property, check whether you’ve accidentally quoted the value.
The for attribute on a <label> element tells the browser which form control the label describes. When a user clicks or taps the label, the browser transfers focus to the associated control. For this to work, the value of for must exactly match the id of a form element such as an <input>, <textarea>, <select>, or <button>.
An empty string ("") is not a valid ID according to the HTML specification. The WHATWG HTML standard requires that an id attribute value must contain at least one character and must not contain ASCII whitespace. Since no element can have an empty-string id, a <label> with for="" can never successfully reference anything, making it both invalid markup and a broken association.
Why this matters
Accessibility: Screen readers rely on the for/id pairing to announce what a form control is for. A label with an empty for attribute creates no programmatic association, meaning assistive technology users may not know what a field is asking for. This directly impacts WCAG compliance.
Usability: A properly associated label expands the clickable area of its form control. For example, clicking a label associated with a checkbox will toggle the checkbox. An empty for attribute breaks this behavior.
Standards compliance: The W3C validator flags this because it violates the HTML specification. Keeping markup valid helps ensure consistent behavior across browsers and future-proofs your code.
How to fix
You have three options:
- Set for to a valid id: Give the associated form control a unique id and reference it in the label’s for attribute.
- Remove for and use implicit association: Wrap the form control inside the <label> element. This creates an implicit association without needing for or id at all.
- Remove the for attribute: If the label is purely decorative or not meant to be associated with a control, simply remove the empty for attribute.
Examples
❌ Empty for attribute (triggers the error)
<label for="">Username:</label>
<input type="text" name="username">
The label has no meaningful association with the input because for="" is not a valid reference.
✅ Fix: Use a valid for/id pair
<label for="username">Username:</label>
<input type="text" id="username" name="username">
The for="username" now matches id="username" on the input, creating an explicit association.
✅ Fix: Use implicit association by nesting
<label>
Username:
<input type="text" name="username">
</label>
Wrapping the input inside the <label> creates an implicit association. No for or id attributes are needed.
❌ Multiple labels with empty for attributes
<form>
<label for="">Email:</label>
<input type="email" name="email">
<label for="">Subscribe to newsletter</label>
<input type="checkbox" name="subscribe">
</form>
✅ Fixed with proper associations
<form>
<label for="email">Email:</label>
<input type="email" id="email" name="email">
<label for="subscribe">Subscribe to newsletter</label>
<input type="checkbox" id="subscribe" name="subscribe">
</form>
Each id must be unique within the document, and each for attribute must reference exactly one id. If your labels are generated by a framework or CMS with empty for values, check the template or component configuration to ensure proper id values are being output.
When the W3C HTML Validator reports that an attribute is “not serializable as XML 1.0,” it means the attribute name contains characters that fall outside the allowed range defined by the XML 1.0 specification. HTML5 documents can be serialized as either HTML or XML (XHTML), and the validator checks that your markup is compatible with both serialization formats. Attribute names in XML 1.0 must start with a letter or underscore and can only contain letters, digits, hyphens, underscores, periods, and certain Unicode characters — they cannot include characters like {, }, @, $, or other symbols commonly found in templating languages.
This issue most frequently appears when a server-side or client-side templating engine (such as Mustache, Handlebars, Angular, Jinja2, or Blade) fails to fully process its expressions before the HTML reaches the browser. Instead of the template placeholder being replaced with a proper value, the raw template syntax ends up in the HTML as a malformed attribute. For example, {{class}} might appear as an attribute name rather than being resolved to its intended value.
Why this matters
- Standards compliance: HTML that isn’t serializable as XML 1.0 cannot be reliably converted to XHTML, which limits interoperability.
- Browser inconsistency: Browsers may handle invalid attribute names unpredictably, potentially ignoring the attribute entirely or misinterpreting surrounding markup.
- Accessibility: Malformed attributes can break ARIA attributes or other accessibility-related markup, making content inaccessible to assistive technologies.
- Tooling and parsing: XML-based tools, RSS feeds, and content syndication systems that consume your HTML will choke on attributes that violate XML naming rules.
How to fix it
- Check for unresolved template expressions. Inspect the rendered HTML (not your source templates) for leftover placeholders like {{...}}, <%= ... %>, @{...}, or similar patterns.
- Ensure proper server-side rendering. Make sure your templating engine is correctly processing all expressions before the HTML is sent to the client.
- Remove invalid characters from attribute names. If you’re using custom attributes, stick to valid data-* attributes with names consisting only of lowercase letters, digits, and hyphens (after the data- prefix).
- Check for typos. A missing = sign, quote, or space can cause a value to be interpreted as an attribute name.
Examples
Unresolved template placeholder in an attribute
This occurs when a template expression isn’t processed and appears literally in the output:
<!-- ❌ Bad: template syntax rendered as attribute name -->
<div {{classBinding}} id="main">
<p>Hello, world!</p>
</div>
The fix is to ensure the template engine resolves the expression. The rendered output should look like this:
<!-- ✅ Good: attribute properly resolved -->
<div class="container" id="main">
<p>Hello, world!</p>
</div>
Typo causing a value to be parsed as an attribute name
A missing equals sign or quotation mark can cause part of a value to become an attribute name with invalid characters:
<!-- ❌ Bad: missing = sign causes "bold}" to be treated as an attribute -->
<p style"font-weight:bold}" class="intro">Welcome</p>
<!-- ✅ Good: proper attribute syntax -->
<p style="font-weight:bold" class="intro">Welcome</p>
Special characters in custom attribute names
Using invalid characters directly in attribute names will trigger this error:
<!-- ❌ Bad: @ and $ are not valid in attribute names -->
<input @change="update" $value="test">
If you need custom attributes, use the standard data-* pattern:
<!-- ✅ Good: valid data attributes -->
<input data-change="update" data-value="test">
Angular-style bindings in static HTML
Frameworks like Angular use special attribute syntax (e.g., [property] or (event)) that is only valid within the framework’s context and will fail validation if rendered directly:
<!-- ❌ Bad: framework-specific syntax in raw HTML -->
<img [src]="imageUrl" (load)="onLoad()">
If you’re generating static HTML, use standard attributes instead:
<!-- ✅ Good: standard HTML attribute -->
<img src="photo.jpg" alt="A photo">
The transform CSS property lets you rotate, scale, skew, or translate an element by modifying its coordinate space. The validator checks inline and embedded CSS for correctness, and it will flag any value it doesn’t recognize as a valid transform value. Common mistakes include:
- Missing units on angles or lengths (e.g., rotate(45) instead of rotate(45deg))
- Typos in function names (e.g., rotatee(10deg) or tranlate(10px))
- Wrong value types (e.g., using a color or a plain number where a function is expected)
- Missing commas or parentheses in function arguments
- Using non-existent functions (e.g., flip(180deg) is not a valid transform function)
- Incorrect number of arguments (e.g., matrix() requires exactly 6 values)
This matters for standards compliance and predictable rendering. While browsers may silently ignore invalid transform values, the element simply won’t be transformed — which can lead to subtle layout bugs that are hard to track down. Catching these errors at validation time helps you fix them before they reach users.
Examples
Invalid: missing angle unit
The rotate() function requires a value with an angle unit like deg, rad, turn, or grad.
<div style="transform: rotate(45);">Rotated text</div>
Fixed: adding the angle unit
<div style="transform: rotate(45deg);">Rotated text</div>
Invalid: typo in function name
<div style="transform: tranlateX(10px);">Shifted text</div>
Fixed: correcting the function name
<div style="transform: translateX(10px);">Shifted text</div>
Invalid: using a non-transform value
A plain number or unrelated keyword is not a valid transform value.
<div style="transform: 200px;">Content</div>
Fixed: using a proper transform function
<div style="transform: translateX(200px);">Content</div>
Invalid: wrong number of arguments for matrix()
The matrix() function requires exactly six comma-separated numbers.
<div style="transform: matrix(1, 2, 3);">Content</div>
Fixed: providing all six arguments
<div style="transform: matrix(1, 0, 0, 1, 0, 0);">Content</div>
Valid transform values reference
Here is a summary of all valid transform functions and the keyword/global values:
<style>
/* Keyword value */
.no-transform { transform: none; }
/* Translate functions */
.move-a { transform: translate(12px, 50%); }
.move-b { transform: translateX(2em); }
.move-c { transform: translateY(3in); }
.move-d { transform: translateZ(2px); }
.move-e { transform: translate3d(12px, 50%, 3em); }
/* Rotate functions */
.spin-a { transform: rotate(0.5turn); }
.spin-b { transform: rotateX(10deg); }
.spin-c { transform: rotateY(10deg); }
.spin-d { transform: rotateZ(10deg); }
.spin-e { transform: rotate3d(1, 2, 3, 10deg); }
/* Scale functions */
.grow-a { transform: scale(2, 0.5); }
.grow-b { transform: scaleX(2); }
.grow-c { transform: scaleY(0.5); }
.grow-d { transform: scaleZ(0.3); }
.grow-e { transform: scale3d(2.5, 1.2, 0.3); }
/* Skew functions */
.lean-a { transform: skew(30deg, 20deg); }
.lean-b { transform: skewX(30deg); }
.lean-c { transform: skewY(1.07rad); }
/* Other functions */
.depth { transform: perspective(500px); }
.matrix-2d { transform: matrix(1, 0, 0, 1, 0, 0); }
.matrix-3d { transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); }
/* Multiple functions chained together */
.combo { transform: translateX(10px) rotate(10deg) translateY(5px); }
</style>
When troubleshooting this error, look at the specific value the validator reports as invalid. Compare it against the valid functions listed above, double-check spelling, ensure all arguments have correct units, and verify that parentheses and commas are properly placed.
The validator reports “Bad value “” for attribute id on element X: An ID must not be the empty string” when any element includes an empty id attribute. Per the HTML standard, id is a global attribute used as a unique document-wide identifier. An empty identifier is not a valid value and is ignored by some features, leading to hard-to-debug issues.
This matters for accessibility and interoperability. Features that depend on IDs—fragment navigation (#target), <label for>, ARIA attributes like aria-labelledby/aria-controls, and DOM APIs such as document.getElementById()—require a non-empty, unique value. Empty IDs break these links, can degrade assistive technology output, and violate conformance, which may hide bugs across browsers.
How to fix:
- If the element doesn’t need an identifier, remove the id attribute entirely.
- If it needs one, provide a non-empty, unique value, e.g., id="main-content".
- Ensure uniqueness across the page; each id must occur only once.
- Use simple, predictable tokens: avoid spaces, prefer lowercase letters, digits, hyphens, and underscores (e.g., feature-1). While the spec allows a broad range of characters, sticking to URL- and selector-friendly characters avoids pitfalls.
Examples
Example that triggers the validator error (empty id)
<div id=""></div>
Correct: remove an unnecessary empty id
<div></div>
Correct: provide a meaningful, unique id
<section id="features"></section>
Problematic label association with empty id (invalid)
<label for="">Email</label>
<input type="email" id="">
Correct label–control association
<label for="email">Email</label>
<input type="email" id="email">
Correct ARIA relationship
<h2 id="pricing-heading">Pricing</h2>
<section aria-labelledby="pricing-heading">
<p>Choose a plan.</p>
</section>
Correct fragment navigation target
<nav>
<a href="#contact">Contact</a>
</nav>
<section id="contact">
<h2>Contact us</h2>
</section>
Minimal full document (validated) demonstrating proper ids
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Valid IDs Example</title>
</head>
<body>
<main id="main-content">
<h1 id="page-title">Welcome</h1>
<p>Jump to the <a href="#details">details</a>.</p>
<section id="details">
<h2>Details</h2>
</section>
<form>
<label for="email">Email</label>
<input id="email" type="email">
</form>
</main>
</body>
</html>
The padding shorthand property sets the padding area on all four sides of an element. It accepts one to four values, each of which must be a <length> (e.g., 10px, 1em), a <percentage>, or 0. Unlike some other CSS properties such as border, outline, or max-width, the padding property has no none keyword in its value syntax.
This is a common mistake because several CSS properties do accept none — for example, border: none, text-decoration: none, and display: none. It’s natural to assume padding: none would work the same way, but the CSS specification simply doesn’t define it for padding. When a browser encounters an invalid value, it ignores the declaration entirely, which means your intended styling won’t be applied and the element may retain its default or inherited padding. This can lead to unexpected layout issues that are difficult to debug.
The same rule applies to the margin property — margin: none is also invalid. Use margin: 0 instead.
How to Fix It
Replace none with 0. You don’t need to include a unit when the value is zero, so padding: 0 is perfectly valid and is the idiomatic way to express “no padding.” You can also use 0 for individual padding properties like padding-top, padding-right, padding-bottom, and padding-left.
If you only want to remove padding on specific sides, target those sides individually rather than using the shorthand.
Examples
❌ Incorrect: Using none with padding
.card {
padding: none;
}
The validator will report: CSS: “padding”: “none” is not a “padding” value. The browser will ignore this declaration.
✅ Correct: Using 0 to remove padding
.card {
padding: 0;
}
✅ Correct: Removing padding on specific sides
.card {
padding-top: 0;
padding-bottom: 0;
}
❌ Incorrect: Using none in inline styles
<div style="padding: none;">Content</div>
✅ Correct: Using 0 in inline styles
<div style="padding: 0;">Content</div>
✅ Correct: Using valid padding values
/* Single value — applies to all four sides */
.card {
padding: 16px;
}
/* Two values — vertical | horizontal */
.card {
padding: 10px 20px;
}
/* Four values — top | right | bottom | left */
.card {
padding: 10px 20px 15px 5px;
}
/* Zero on top/bottom, 1em on left/right */
.card {
padding: 0 1em;
}
CSS length values must always pair a number with a unit — writing just px, em, %, or any other unit without a preceding number is meaningless to the browser and will be ignored. This typically happens due to a typo, a copy-paste error, or a build tool / template that outputs a unit without its corresponding numeric value (e.g., a variable that resolved to an empty string concatenated with px).
When the W3C validator encounters margin: px in an inline style attribute, it flags the error because px on its own does not match any valid CSS value for the margin property. Valid values include lengths like 10px or 2em, percentages like 5%, the keyword auto, or the number 0 (which doesn’t need a unit). Browsers will discard the invalid declaration, meaning your intended spacing won’t be applied — potentially breaking your layout in subtle ways that are hard to debug.
This issue also applies to other CSS properties that accept length values, such as padding, width, height, top, left, border-width, font-size, and many more. The fix is always the same: ensure every unit has an accompanying number.
How to Fix It
- Add the missing number before the unit: change px to something like 10px, 1.5em, or 20%.
- Use 0 without a unit if you want zero margin — writing margin: 0 is valid and preferred over margin: 0px.
- Use a keyword if appropriate, such as margin: auto for centering.
- Remove the declaration if the margin value was unintentional or unnecessary.
If the value comes from a preprocessor, template engine, or JavaScript, check that the variable being interpolated is not empty or undefined before it gets concatenated with the unit string.
Examples
Incorrect: Unit Without a Number
<div style="margin: px;">Content</div>
The value px has no number, so this is invalid CSS.
Correct: Number Paired With Unit
<div style="margin: 10px;">Content</div>
Correct: Zero Margin (No Unit Needed)
<div style="margin: 0;">Content</div>
Correct: Using a Keyword
<div style="margin: auto;">Content</div>
Incorrect in an External Stylesheet
This same error can appear in a <style> block or linked stylesheet:
<style>
.card {
margin: px;
}
</style>
Correct in an External Stylesheet
<style>
.card {
margin: 16px;
}
</style>
Watch Out for Template Variables
A common cause in templating systems is an empty variable:
<!-- If spacing is empty, this produces "margin: px;" -->
<div style="margin: {{ spacing }}px;">Content</div>
To prevent this, ensure the variable contains the full value including the number, or add a fallback:
<div style="margin: 16px;">Content</div>
The CSS cursor property controls the appearance of the mouse pointer when it hovers over an element. The value hand was introduced by early versions of Internet Explorer (IE 5.5 and earlier) as a proprietary extension to show a pointing-hand cursor over clickable elements. However, this value was never part of any CSS specification, and no other browser adopted it. The W3C-standard equivalent is pointer, which has been supported by all browsers — including Internet Explorer 6 and later — for over two decades.
When the W3C validator encounters cursor: hand, it flags it as an invalid value because hand does not exist in the CSS specification’s list of accepted cursor values. While some legacy browsers may still interpret it, modern browsers will simply ignore the invalid declaration, meaning your clickable elements won’t display the expected hand cursor for many users.
Beyond validation, using non-standard CSS values can cause inconsistent behavior across browsers and platforms. The pointer value is universally supported and is the correct way to signal that an element is interactive, such as a link, button, or any custom clickable region.
To fix this issue, replace every instance of cursor: hand with cursor: pointer in your stylesheets. If you need to support extremely old versions of Internet Explorer (IE 5.5 or earlier), you can declare both values — the browser will use whichever it recognizes — though this is almost never necessary today.
Examples
Invalid CSS
The value hand is not recognized by the CSS specification and will trigger a validation error:
.clickable {
cursor: hand;
}
Valid CSS
Use the standard pointer value instead:
.clickable {
cursor: pointer;
}
Using it in context with HTML
<style>
.card {
padding: 16px;
border: 1px solid #ccc;
cursor: pointer;
}
</style>
<div class="card">
Click me to view details
</div>
Legacy fallback (rarely needed)
If for some reason you must support IE 5.5 or earlier alongside modern browsers, you can provide both declarations. The browser will apply the last value it understands:
.clickable {
cursor: hand;
cursor: pointer;
}
Note that this fallback pattern will still produce a validation warning for the hand value. In practice, there is virtually no reason to support browsers this old, so using cursor: pointer alone is the recommended approach.
Common cursor values
For reference, here are some of the most frequently used valid cursor values defined in the CSS specification:
- auto — the browser determines the cursor based on context (default behavior)
- default — the platform’s default cursor, typically an arrow
- pointer — a pointing hand, indicating a link or clickable element
- text — an I-beam, indicating selectable text
- move — indicates something can be moved
- not-allowed — indicates an action is not permitted
- grab / grabbing — indicates a draggable element
- crosshair — a precise selection cursor
- wait — indicates the program is busy
- help — indicates help is available
The full list of accepted values is defined in the CSS Basic User Interface Module specification.
An invalid value was assigned to the CSS right property, meaning the validator does not recognize the value you provided.
The CSS right property specifies the horizontal offset of a positioned element from the right edge of its containing block. It only accepts specific value types: a length (e.g., 10px, 2em), a percentage (e.g., 50%), auto, inherit, initial, unset, or revert. Any other value — such as a typo, a missing unit, or an unsupported keyword — will trigger this validation error.
A common mistake is forgetting the unit after a number. In CSS, 0 is the only length value that can be written without a unit. Writing something like right: 10 instead of right: 10px is invalid. Another common cause is using an unrecognized keyword or passing a value meant for a different property.
Invalid Example
<div style="position: absolute; right: 10;">
This box has an invalid right value.
</div>
The value 10 is missing a unit, so the validator rejects it.
Fixed Example
<div style="position: absolute; right: 10px;">
This box is correctly positioned.
</div>
Adding a valid unit like px, em, rem, or % resolves the issue. If you intended no offset, use right: 0 or right: auto.
The padding property accepts one or more length values, percentages, or the keyword 0. A valid length value always consists of a number immediately followed by a unit identifier, such as 10px, 1.5em, or 2rem. Writing just px without a preceding number is meaningless to the CSS parser — it’s like saying “pixels” without specifying how many. The browser will discard the invalid declaration entirely, which means the element will fall back to its default or inherited padding, potentially breaking your layout in unexpected ways.
This error commonly occurs due to:
- Typos or accidental deletion — the numeric part of the value was inadvertently removed during editing.
- Templating or build tool issues — a dynamic value (e.g., from a variable or CMS field) resolved to an empty string, leaving only the px suffix behind.
- Copy-paste mistakes — copying a snippet and forgetting to update the placeholder value.
Because the W3C validator flags this in inline style attributes, it means invalid CSS is embedded directly in your HTML. Fixing it improves standards compliance and ensures consistent rendering across browsers.
How to Fix
- Add a numeric value before the unit: change px to something like 10px, 1em, or 5%.
- Use 0 without a unit if you want zero padding — writing padding: 0; is valid and preferred over padding: 0px;.
- Check dynamic values — if the number comes from a variable or template expression, make sure it outputs a valid number and isn’t empty.
Examples
Incorrect: Unit Without a Number
<div style="padding: px;">Content</div>
The validator reports that px is not a valid padding value because no number precedes the unit.
Correct: Numeric Value With Unit
<div style="padding: 10px;">Content</div>
Correct: Zero Padding (No Unit Needed)
<div style="padding: 0;">Content</div>
When the value is 0, no unit is required since zero pixels, zero ems, and zero percent are all identical.
Correct: Multiple Padding Values
<div style="padding: 8px 16px;">Content</div>
This sets 8px of vertical padding and 16px of horizontal padding — both are valid length values.
Incorrect in External CSS
The same problem can appear in a stylesheet linked from your HTML:
.card {
padding: px;
}
Fixed in External CSS
.card {
padding: 12px;
}
Watch for Template-Generated Values
If you use a templating system, double-check that the numeric portion actually renders. For example, a template like this could produce the error if spacing is empty:
<!-- If spacing is empty, this becomes "padding: px;" -->
<div style="padding: {{ spacing }}px;">Content</div>
Make sure the variable always resolves to a valid number, or provide a fallback value.
The CSS filter property accepts a specific set of filter functions defined in the CSS Filter Effects Module. When the validator encounters a value it doesn’t recognize — such as the legacy IE progid:DXImageTransform.Microsoft. syntax, a made-up function name, or an incorrectly formatted value — it flags it as invalid.
The standard filter functions are: blur(), brightness(), contrast(), drop-shadow(), grayscale(), hue-rotate(), invert(), opacity(), saturate(), sepia(), and url() (for referencing SVG filters). The property also accepts the keyword none. Any value outside this set will trigger the validation error.
Why this matters
Using non-standard filter values creates several problems:
- Browser compatibility: Legacy or proprietary filter syntax (such as Microsoft’s filter: alpha(opacity=50) or filter: FlipH) only works in old versions of Internet Explorer and is ignored by all modern browsers.
- Standards compliance: Invalid CSS can cause parsers to discard the entire declaration or even the surrounding rule block, potentially breaking other styles.
- Future-proofing: Non-standard values may stop working entirely as browsers drop legacy support, leaving your design broken with no fallback.
How to fix it
- Identify the invalid value in the error message.
- Determine what visual effect you’re trying to achieve.
- Replace the invalid value with the corresponding standard CSS filter function.
- If you’re using legacy IE opacity filters, switch to the standard opacity property instead.
Examples
❌ Invalid: Legacy Microsoft filter syntax
<style>
.overlay {
filter: alpha(opacity=50);
}
</style>
✅ Fixed: Use standard opacity property
<style>
.overlay {
opacity: 0.5;
}
</style>
❌ Invalid: Misspelled or non-existent filter function
<style>
.photo {
filter: gray();
}
</style>
✅ Fixed: Use the correct grayscale() function
<style>
.photo {
filter: grayscale(100%);
}
</style>
❌ Invalid: Vendor-prefixed or proprietary value
<style>
.card {
filter: progid:DXImageTransform.Microsoft.Blur(pixelradius=5);
}
</style>
✅ Fixed: Use the standard blur() function
<style>
.card {
filter: blur(5px);
}
</style>
❌ Invalid: Bare value without a function
<style>
.image {
filter: 50%;
}
</style>
✅ Fixed: Wrap the value in the appropriate function
<style>
.image {
filter: brightness(50%);
}
</style>
Combining multiple filters
You can chain multiple standard filter functions in a single declaration by separating them with spaces:
<style>
.hero-image {
filter: contrast(120%) brightness(90%) blur(1px);
}
</style>
If none of the built-in filter functions achieve the effect you need, you can reference a custom SVG filter using the url() function, which is also a valid filter value:
<svg xmlns="http://www.w3.org/2000/svg" class="visually-hidden">
<filter id="custom-effect">
<feColorMatrix type="matrix" values="0.3 0.3 0.3 0 0
0.3 0.3 0.3 0 0
0.3 0.3 0.3 0 0
0 0 0 1 0"/>
</filter>
</svg>
<style>
.filtered {
filter: url(#custom-effect);
}
</style>
CSS math functions like calc(), min(), max(), and clamp() follow strict rules about how operands and operators interact. The error “one operand must be a number” most commonly fires in two scenarios: either an operand is missing entirely (e.g., calc(100% - )), or both operands in a multiplication or division carry units (e.g., calc(10px * 5px)). The CSS Values and Units specification requires that for * (multiplication), at least one side must be a unitless <number>. For / (division), the right-hand side must always be a unitless <number>. You cannot multiply two lengths together or divide a length by another length within calc().
This matters for several reasons. Browsers will discard the entire property declaration if the calc() expression is invalid, which can cause layout breakage or fallback to unexpected default values. The W3C validator catches these errors in inline style attributes and embedded <style> blocks, helping you identify expressions that will silently fail in production. Fixing these issues ensures predictable rendering across all browsers.
How the rules work
- Addition and subtraction (+, -): Both operands must have compatible types (e.g., both lengths, or both percentages, or a mix of length and percentage). Both must be present.
- Multiplication (*): At least one operand must be a plain <number> (unitless). You can write calc(10px * 3) or calc(3 * 10px), but not calc(10px * 5px).
- Division (/): The right-hand operand must be a plain <number> (unitless and non-zero). You can write calc(100px / 2), but not calc(100px / 2px).
Examples
Missing operand
A common mistake is leaving out a value on one side of an operator:
<!-- ❌ Wrong: missing operand after the minus sign -->
<div style="width: calc(100% - );"></div>
<!-- ✅ Fixed: both operands are present -->
<div style="width: calc(100% - 50px);"></div>
Multiplying two values with units
You cannot multiply two unit-bearing values together, because the result would be a meaningless type like “px²”:
<!-- ❌ Wrong: both operands have units -->
<div style="width: calc(10px * 5px);"></div>
<!-- ✅ Fixed: one operand is a unitless number -->
<div style="width: calc(10px * 5);"></div>
Dividing by a value with units
The divisor in a / operation must be a unitless number:
<!-- ❌ Wrong: dividing by a value with units -->
<div style="height: calc(500px / 2em);"></div>
<!-- ✅ Fixed: divisor is a unitless number -->
<div style="height: calc(500px / 2);"></div>
Nested calc() with a missing value
Errors can hide inside nested expressions:
<!-- ❌ Wrong: inner calc has an incomplete expression -->
<p style="margin-top: calc(2rem + calc(100% * ));"></p>
<!-- ✅ Fixed: all operands are present and valid -->
<p style="margin-top: calc(2rem + calc(100% * 0.5));"></p>
Using variables or keywords where a number is expected
Sometimes a typo or misunderstanding leads to a non-numeric token where a number is required:
<!-- ❌ Wrong: "auto" is not a valid operand in calc() -->
<div style="width: calc(auto * 2);"></div>
<!-- ✅ Fixed: use a numeric value or percentage -->
<div style="width: calc(100% * 2);"></div>
To resolve this error, review every calc(), min(), max(), and clamp() expression in your inline styles and stylesheets. Confirm that all operators have valid operands on both sides, that * always has at least one unitless number, and that / always has a unitless number on the right. If you’re building expressions dynamically (e.g., via JavaScript or a templating engine), double-check that variables are being interpolated correctly and not producing empty or invalid values.
Character references are how HTML represents special characters that would otherwise be interpreted as markup or that aren’t easily typed on a keyboard. They come in three forms:
- Named references like &, <, ©
- Decimal numeric references like <, ©
- Hexadecimal numeric references like <, ©
All three forms share the same structure: they begin with & and must end with ;. When you omit the trailing semicolon, the HTML parser enters error recovery mode. Depending on the context, it may still resolve the reference (browsers are lenient), but this behavior is not guaranteed and varies across situations. For example, © without a semicolon might still render as ©, but ¬it could be misinterpreted as the ¬ (¬) reference followed by it, producing unexpected output like “¬it” instead of the literal text “¬it”.
Why this matters
- Unpredictable rendering: Without the semicolon, browsers use heuristic error recovery that can produce different results depending on surrounding text. What looks fine today might break with different adjacent characters.
- Standards compliance: The WHATWG HTML specification requires the semicolon terminator. Omitting it is a parse error.
- Maintainability: Other developers (or future you) may not realize the ampersand was intended as a character reference, making the code harder to read and maintain.
- Data integrity: In URLs within href attributes, a missing semicolon on a character reference can corrupt query parameters and produce broken links.
How to fix it
- Add the missing semicolon to the end of every character reference.
- If you meant a literal ampersand, use & instead of a bare &. This is especially common in URLs with query strings.
- Search your document for patterns like &something without a trailing ; to catch all instances.
Examples
❌ Missing semicolon on named references
<p>5 < 10 and 10 > 5</p>
<p>© 2024 All rights reserved</p>
✅ Properly terminated named references
<p>5 < 10 and 10 > 5</p>
<p>© 2024 All rights reserved</p>
❌ Missing semicolon on numeric references
<p>The letter A: A</p>
<p>Hex example: A</p>
✅ Properly terminated numeric references
<p>The letter A: A</p>
<p>Hex example: A</p>
❌ Bare ampersand in a URL (common mistake)
<a href="https://example.com/search?name=alice&age=30">Search</a>
Here the validator sees &age and tries to interpret it as a character reference without a semicolon.
✅ Escaped ampersand in a URL
<a href="https://example.com/search?name=alice&age=30">Search</a>
❌ Ambiguous reference causing wrong output
<p>The entity ¬it; doesn't exist, but ¬ without a semicolon resolves to ¬</p>
✅ Use & when you want a literal ampersand
<p>The text &notit is displayed literally when properly escaped.</p>
A quick rule of thumb: every & in your HTML should either be the start of a complete, semicolon-terminated character reference, or it should itself be written as &.
The border shorthand property accepts up to three values: a width (e.g., 1px), a style (e.g., solid), and a color (e.g., black). When the validator encounters "undefined" in the color position, it rightfully rejects it because undefined is not a recognized CSS color keyword, hex value, or color function.
This issue most commonly appears in projects that use JavaScript to dynamically set inline styles. When a variable intended to hold a color value is undefined—perhaps because it wasn’t initialized, a configuration value is missing, or a function didn’t return a result—the rendered HTML ends up with a literal style="border: 1px solid undefined" in the markup. Build tools, templating engines, or server-side rendering can also produce this output if a variable isn’t properly resolved.
Beyond failing validation, this is a real problem because browsers will discard the entire border declaration when they encounter an invalid value. This means the border won’t render at all, which may break your layout or visual design in ways that are hard to debug. Ensuring valid CSS values keeps your styling predictable across all browsers.
How to fix it
- Check for dynamic values. If the color is set via JavaScript or a templating engine, ensure the variable always resolves to a valid color string. Add fallback values or default assignments.
- Replace the invalid value. Substitute undefined with a proper CSS color — a named color (red, black), a hex code (#333), an rgb() or hsl() function, or even transparent or currentcolor.
- Remove the declaration. If no border is needed, remove the border property entirely rather than leaving an invalid value in place.
Examples
Incorrect: literal undefined as a color value
<div style="border: 1px solid undefined;">Content</div>
The validator rejects undefined because it is not a valid CSS color.
Incorrect: JavaScript producing undefined in markup
<script>
const borderColor = undefined; // missing configuration
document.getElementById("box").style.border = "2px dashed " + borderColor;
</script>
This produces border: 2px dashed undefined on the element.
Correct: using a valid color value
<div style="border: 1px solid black;">Content</div>
Correct: using a hex code or rgb() function
<div style="border: 2px dashed #ff6600;">Content</div>
<div style="border: 3px dotted rgb(0, 128, 255);">Content</div>
Correct: providing a fallback in JavaScript
<div id="box">Content</div>
<script>
const borderColor = getUserColor() || "#333";
document.getElementById("box").style.border = "2px solid " + borderColor;
</script>
By using || "#333", you ensure a valid color is always applied even when getUserColor() returns undefined.
Correct: using separate border properties
If you prefer more granular control, you can define each border sub-property individually:
<div style="border-width: 1px; border-style: solid; border-color: black;">Content</div>
Valid border shorthand reference
The border shorthand follows this pattern:
selector {
border: <width> <style> <color>;
}
- Width: 1px, 2px, thin, medium, thick
- Style: solid, dashed, dotted, double, groove, ridge, inset, outset, none
- Color: any valid CSS color — named colors (red, blue), hex (#000), rgb(), hsl(), currentcolor, or transparent
All three values are optional in the shorthand, but any value you do include must be valid. The string undefined is never a valid CSS value. If your styles are generated dynamically, always validate or sanitize the output before it reaches the HTML.
Ready to validate your sites?
Start your free trial today.