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.
::ng-deep is a pseudo-class combinator specific to Angular's view encapsulation system. It tells Angular's compiler to disable style encapsulation for a particular CSS rule, allowing that rule to penetrate into child component views. Because it is not defined in any W3C or WHATWG CSS specification, the CSS validator flags it as an unknown pseudo-element or pseudo-class.
This is important to understand for several reasons:
- It's not a standard CSS feature. No browser natively understands
::ng-deep. Angular's build toolchain processes and removes it at compile time, rewriting the selector before it reaches the browser. The validator checks against CSS specifications and rightfully does not recognize it. - It's deprecated within Angular itself. The Angular team has deprecated
::ng-deepand plans to remove it in a future version. Continued use ties your codebase to a feature with no long-term support. - It can cause unintended global style leakage. When combined with
:hostimproperly or used without care,::ng-deepcan bleed styles into components where they weren't intended, making your application harder to maintain.
How to Fix It
There are several approaches depending on your situation:
1. Accept the Validation Warning
If you're working in an Angular project and need ::ng-deep temporarily, you can acknowledge this as a known framework-specific warning. The validator is technically correct — the selector isn't valid CSS — but Angular's compiler handles it before it reaches the browser.
2. Use Global Stylesheets
Move the styles that need to cross component boundaries into a global stylesheet (like styles.css). Global styles are not encapsulated and naturally apply to all components.
3. Set ViewEncapsulation to None
Disable view encapsulation on the component that needs to style its children. This makes all of that component's styles global in scope, removing the need for ::ng-deep.
4. Use CSS Custom Properties (Recommended)
The most standards-compliant approach is to use CSS custom properties (variables) to create a theming API for your components. Custom properties naturally inherit through the DOM tree, crossing shadow DOM and Angular encapsulation boundaries.
Examples
❌ Using ::ng-deep (Triggers the Validation Warning)
:host::ng-deep.child-button{
background-color: blue;
color: white;
}
The validator does not recognize ::ng-deep and reports the error.
✅ Using a Global Stylesheet Instead
In your global styles.css file, target the element with a specific class or selector:
app-parent.child-button{
background-color: blue;
color: white;
}
This avoids ::ng-deep entirely by placing the rule outside of component-scoped styles.
✅ Using CSS Custom Properties
Define customizable properties in the child component's CSS:
/* Child component styles */
.child-button{
background-color:var(--child-button-bg, gray);
color:var(--child-button-color, black);
}
Then set the values from the parent component's CSS:
/* Parent component styles */
:host{
--child-button-bg: blue;
--child-button-color: white;
}
This approach is fully standards-compliant, passes CSS validation, and creates a clean styling API between components. CSS custom properties inherit naturally through the DOM, so they work across component boundaries without breaking encapsulation.
✅ Using ::part() for Web Components
If your child components use shadow DOM (or you're migrating toward web components), the standard ::part() pseudo-element lets you expose specific elements for external styling:
/* Parent styles targeting an exposed part */
child-component::part(button){
background-color: blue;
color: white;
}
The ::part() pseudo-element is a W3C standard and fully recognized by the CSS validator.
CSS pseudo-classes (like :hover, :focus, :nth-child()) select elements based on their state or position, while pseudo-elements (like ::before, ::after, ::placeholder) target specific parts of an element. The CSS specification distinguishes between the two by using a single colon for pseudo-classes and a double colon for pseudo-elements. While browsers still support the legacy single-colon syntax for older pseudo-elements like :before and :after for backward compatibility, the validator expects the modern double-colon form ::before and ::after.
Why This Matters
Standards compliance. The double-colon syntax for pseudo-elements was introduced in CSS3 to clearly distinguish pseudo-elements from pseudo-classes. Using the correct syntax makes your code more readable and future-proof.
Catching real bugs. A misspelled pseudo-class like :foucs or :hovr will silently fail — the browser simply ignores the entire rule. The validator catches these typos before they cause mysterious styling issues in production.
Validator profile limitations. The W3C CSS validator checks your styles against a specific CSS profile. Newer selectors like :has(), :is(), or :where() may not be recognized if the validator is set to an older profile like CSS Level 2.1 or even CSS Level 3. Vendor-prefixed selectors like ::-webkit-input-placeholder or ::-moz-placeholder are never part of any standard profile and will always be flagged.
Common Causes
- Typos —
:hovr,:foucs,::plceholder, etc. - Single colon on pseudo-elements —
:before,:after,:first-line,:first-letterinstead of their double-colon equivalents. - Vendor-prefixed selectors —
::-webkit-input-placeholder,::-moz-selection,:-ms-input-placeholder. - Modern selectors on older profiles —
:has(),:is(),:where(),::marker,:focus-visiblemay not be recognized depending on the validator's CSS level setting.
How to Fix
- Check spelling of all pseudo-classes and pseudo-elements.
- Use double colons for pseudo-elements:
::before,::after,::first-line,::first-letter,::placeholder,::marker,::selection. - Replace vendor-prefixed selectors with their standard equivalents. If you still need the prefix for browser support, place the standard version alongside it and accept that the prefixed line may produce a warning.
- Update the validator profile to a newer CSS level if you're intentionally using modern selectors like
:has()or:focus-visible.
Examples
Incorrect — triggers the warning
<style>
/* Typo in pseudo-class */
a:hovr{
color: red;
}
/* Single colon on pseudo-element */
p:before{
content:"→ ";
}
/* Vendor-prefixed pseudo-element without standard version */
input::-webkit-input-placeholder{
color: gray;
}
</style>
Each of these rules will trigger an "Unknown pseudo-element or pseudo-class" warning. The first is a simple typo, the second uses outdated single-colon syntax, and the third is a non-standard vendor prefix.
Correct — valid CSS
<style>
/* Fixed typo */
a:hover{
color: red;
}
/* Double colon for pseudo-element */
p::before{
content:"→ ";
}
/* Standard pseudo-element */
input::placeholder{
color: gray;
}
</style>
Handling modern selectors
Some modern pseudo-classes like :has() and :focus-visible are well-supported in browsers but may not yet be recognized by the validator. If you need to use them, you can acknowledge the warning or structure your CSS so the modern selector enhances rather than replaces base styles:
<style>
/* Base style that always applies */
.card{
border:1px solid transparent;
}
/* Enhancement using :has() — may warn in the validator */
.card:has(img){
border-color:#ccc;
}
/* :focus-visible for keyboard-only focus rings */
button:focus-visible{
outline:2px solid blue;
}
</style>
These selectors are valid CSS and work in modern browsers. If the validator flags them, consider switching the validator's profile to the latest CSS level, or treat the warnings as informational rather than errors.
The @container at-rule enables container queries, allowing you to apply styles to elements based on the size or inline-size of a parent container rather than the viewport. It was introduced as part of the CSS Containment Module Level 3 specification and has been supported in all major browsers (Chrome, Edge, Firefox, Safari) since early 2023.
The W3C CSS validator uses its own CSS parsing engine, which sometimes lags behind the latest CSS specifications. Because @container is relatively new compared to long-established at-rules like @media or @keyframes, the validator may flag it as unrecognized. This does not mean your CSS is invalid or broken — it simply means the validator hasn't caught up with the spec yet.
Why This Warning Appears
The W3C validator checks your CSS against known grammar rules. When it encounters an at-rule it doesn't have in its internal dictionary, it reports it as unrecognized. Other modern CSS features like @layer and @property have historically triggered the same kind of false positive before being added to the validator's parser.
Since this is a validator limitation and not an actual code issue, there's no required "fix." However, you should still make sure your @container usage is syntactically correct and that you've properly set up containment on the parent element.
How Container Queries Work
For @container to function, a parent element must be designated as a containment context using the container-type property (or the container shorthand). Without this, the browser won't know which ancestor to query against.
Examples
Correct usage of @container
The parent element needs container-type set to inline-size or size so its descendants can query against it:
<divclass="card-wrapper">
<divclass="card">
<h2>Title</h2>
<p>Some content here.</p>
</div>
</div>
.card-wrapper{
container-type: inline-size;
container-name: card-container;
}
@container card-container (min-width:400px){
.card{
display: flex;
gap:1rem;
}
}
In this example, .card-wrapper is established as a containment context. When its inline size is at least 400px, the .card inside switches to a flex layout. The validator may flag the @container block, but this CSS is perfectly valid and works in all modern browsers.
Using @container without a named container
You can omit the container name, and the query will match the nearest ancestor with a container-type set:
.sidebar{
container-type: inline-size;
}
@container(max-width:300px){
.sidebar-nav{
flex-direction: column;
}
}
Common mistake: forgetting container-type
If you use @container without declaring a containment context on a parent, the query will never match and your styles won't apply. This won't cause a validator error, but it's a logical bug:
/* Missing container-type — the @container query has nothing to query against */
.wrapper{
max-width:600px;
}
@container(min-width:400px){
.content{
font-size:1.25rem;
}
}
The fix is to add container-type to the intended parent:
.wrapper{
max-width:600px;
container-type: inline-size;
}
@container(min-width:400px){
.content{
font-size:1.25rem;
}
}
What You Should Do
- Verify your syntax — make sure you're using
container-typeon a parent element and that your@containerquery follows the correct grammar. - Ignore the validator warning — this is a known limitation of the W3C CSS validator. Your CSS is valid per the specification.
- Check browser support —
@containeris supported in Chrome 105+, Edge 105+, Firefox 110+, and Safari 16+. If you need to support older browsers, consider using@containeras a progressive enhancement alongside a fallback layout.
The @font-feature-values at-rule lets you define human-readable names for OpenType font feature indexes, which you can then reference using properties like font-variant-alternates. For example, instead of remembering that swash index 1 maps to a "fancy" style, you can define a named value and use it semantically throughout your CSS. This is a legitimate and useful feature defined in the CSS Fonts Module Level 4 specification.
The validation error occurs because the W3C CSS validator does not always keep pace with newer CSS specifications. The @font-feature-values rule, along with its associated feature type blocks like @swash, @styleset, @character-variant, @ornaments, @annotation, and @stylistic, may simply not be in the validator's recognized grammar yet. This does not mean your CSS is broken or invalid — it means the validator has a gap in its coverage.
That said, there are practical reasons to consider alternatives. If you need to pass strict W3C validation (for example, as a project requirement or contractual obligation), or if you need to support older browsers that lack @font-feature-values support, the font-feature-settings property offers a more widely recognized way to activate OpenType features. The tradeoff is that font-feature-settings uses raw four-character OpenType feature tags instead of friendly names, making it less readable but more portable.
How to Fix
You have several options:
- Ignore the warning. If your target browsers support
@font-feature-values, the CSS is valid per the spec. The validator error is a false positive. - Move the at-rule to an external stylesheet. If you're validating HTML and the CSS is in a
<style>block, moving it to an external.cssfile may help you separate concerns and skip CSS validation during HTML checks. - Replace with
font-feature-settings. Use the lower-level property to activate OpenType features directly by their tag codes.
Examples
Code that triggers the validation error
@font-feature-values"MyFamily"{
@swash{
fancy:1;
}
}
p{
font-family:"MyFamily", serif;
font-variant-alternates:swash(fancy);
}
The validator does not recognize @font-feature-values and flags it as an error, even though this is spec-compliant CSS.
Fixed: Using font-feature-settings instead
<!DOCTYPE html>
<htmllang="en">
<head>
<title>Font Feature Example</title>
<style>
p{
font-family:"MyFamily", serif;
font-feature-settings:"swsh"1;
}
</style>
</head>
<body>
<p>This text uses OpenType swash glyphs via font-feature-settings.</p>
</body>
</html>
The font-feature-settings property accepts OpenType feature tags directly. Common tags include "swsh" for swashes, "smcp" for small caps, "liga" for standard ligatures, and "onum" for oldstyle numerals. This approach avoids the unrecognized at-rule error entirely.
Fixed: Keeping @font-feature-values with a fallback
If you want to use the more readable @font-feature-values syntax while also providing fallback support, you can combine both approaches:
p{
font-family:"MyFamily", serif;
font-feature-settings:"swsh"1;
font-variant-alternates:swash(fancy);
}
@font-feature-values"MyFamily"{
@swash{
fancy:1;
}
}
Browsers that understand font-variant-alternates and @font-feature-values will use the named value. Others will fall back to font-feature-settings. The validation error will persist with this approach, but your CSS will be robust and spec-compliant regardless.
The @media screen rule without a condition after the media type is invalid CSS syntax and will be flagged by the W3C validator.
A @media rule requires either a complete media query or a media type combined with a media feature expression. Writing @media screen alone followed by a block is actually valid CSS, so this error typically appears when the syntax inside the rule is malformed, the rule is missing curly braces, or extra characters appear between screen and the opening brace.
Common causes include:
- A missing opening or closing curly brace
{}around the media block. - Stray characters or typos between the media type and the brace.
- Placing
@mediarules inside astyleattribute (inline styles do not support at-rules). - The CSS appears inside an HTML context where the validator cannot parse it correctly, such as a malformed
<style>element.
If the intent is to target screens of a specific size, a media feature expression is required, like @media screen and (min-width: 768px). If the intent is to target all screen devices with no further conditions, @media screen is valid CSS on its own, and the real problem is likely a syntax error nearby.
Example with the issue
<style>
@media screen
.container{
width:80%;
}
</style>
The opening curly brace for the @media block is missing, so the validator cannot recognize the rule.
Fixed example
<style>
@media screen {
.container{
width:80%;
}
}
</style>
If the goal is to restrict styles to a specific viewport width, add a media feature:
<style>
@media screen and(min-width:768px){
.container{
width:80%;
}
}
</style>
Both examples use properly matched curly braces and valid @media syntax, which resolves the validator error.
The @tailwind directive is used in Tailwind CSS source files to inject Tailwind's generated styles into your stylesheet. Common usages include @tailwind base;, @tailwind components;, and @tailwind utilities;. These directives act as placeholders that Tailwind's build tool (such as the Tailwind CLI or PostCSS plugin) replaces with actual CSS rules during compilation.
The W3C CSS Validator checks stylesheets against official CSS specifications maintained by the W3C. Since @tailwind is not defined in any CSS specification — it's a framework-specific extension — the validator correctly flags it as unrecognized. This doesn't mean your CSS is broken or will cause problems in browsers; it simply means the validator doesn't know what @tailwind is.
This distinction matters because the @tailwind directives should never appear in production CSS served to browsers. If you're seeing this validation error on a live website, it could indicate one of two things: either you're linking directly to your uncompiled Tailwind source file (which is a problem), or the validator is checking your source CSS rather than the compiled output.
How to Fix It
Ensure you're serving compiled CSS
The most important step is to make sure your build pipeline is correctly processing your Tailwind source files. The compiled output should contain only standard CSS — no @tailwind directives. Verify that your <link> tags point to the compiled CSS file, not the source file.
Use the Tailwind CDN or CLI correctly
If you're using the Tailwind CLI, run the build command to generate a compiled stylesheet and reference that file in your HTML. The compiled file will contain only valid CSS.
Consider suppressing the warning
If the validator is checking your source CSS (for example, inline <style> blocks that get processed client-side), and you're confident the directives are being handled correctly, you can safely suppress or ignore this specific warning in your validation reports.
Examples
Source CSS that triggers the warning
This is a typical Tailwind CSS source file that the validator will flag:
@tailwind base;
@tailwind components;
@tailwind utilities;
.custom-button{
padding:0.5rem1rem;
border-radius:0.25rem;
}
Each @tailwind line will produce an "Unrecognized at-rule" warning from the W3C Validator.
Correct approach: serve compiled CSS
After running the Tailwind build process, the output file contains only standard CSS:
*,::before,::after{
box-sizing: border-box;
}
.custom-button{
padding:0.5rem1rem;
border-radius:0.25rem;
}
.flex{
display: flex;
}
.text-center{
text-align: center;
}
Reference this compiled file in your HTML:
<!DOCTYPE html>
<htmllang="en">
<head>
<metacharset="utf-8">
<title>My Page</title>
<linkrel="stylesheet"href="css/output.css">
</head>
<body>
<pclass="text-center">Hello, world!</p>
</body>
</html>
Avoid linking to uncompiled source files
This is incorrect — it links directly to the source file containing @tailwind directives:
<!-- Don't do this -->
<linkrel="stylesheet"href="css/input.css">
Instead, always link to the build output:
<!-- Do this -->
<linkrel="stylesheet"href="css/output.css">
By ensuring your production site serves only the compiled CSS output, you eliminate the @tailwind at-rule warnings entirely and deliver valid, standards-compliant stylesheets to your users.
The @view-transition at-rule is valid CSS but is not yet recognized by the W3C CSS validator because it is a relatively new feature defined in the CSS View Transitions Module Level 2 specification.
The @view-transition at-rule opts a document into cross-document view transitions when navigating between two same-origin pages. It is placed in the CSS of the destination page (the page being navigated to) and accepts a navigation descriptor that controls when the transition activates.
@view-transition{
navigation: auto;
}
The navigation descriptor accepts these values:
none— no cross-document view transition occurs (default).auto— the transition activates for same-origin navigations where the navigation type is traverse, push, or replace, as long as the navigation does not include a cross-origin redirect.
Because the W3C CSS validator has not yet added support for this at-rule, the warning cannot be fixed by changing your code. The CSS itself is correct per the specification. Browser support is available in Chromium-based browsers (Chrome 126+, Edge 126+).
You can safely ignore this validator warning. If you want a completely clean validation output, move the @view-transition rule into a separate stylesheet so it does not interfere with validation of the rest of your CSS, or suppress the warning in your CI pipeline.
The vertical-align property controls the vertical positioning of inline-level elements (like <span>, <img>, and <a>) and table-cell elements (<td>, <th>) relative to their surrounding content or cell. Unlike some other CSS properties (such as float or border), vertical-align has no none keyword. Attempting to use none results in an invalid declaration that browsers will ignore, meaning the element will fall back to the default value of baseline.
This mistake often happens when a developer wants to "reset" or "remove" vertical alignment. Since there is no none value, the correct approach is to either set vertical-align: baseline (the initial value) or remove the vertical-align declaration altogether.
The valid keyword values for vertical-align are:
baseline— aligns the element's baseline with the parent's baseline (default)sub— aligns as a subscriptsuper— aligns as a superscripttext-top— aligns with the top of the parent's fonttext-bottom— aligns with the bottom of the parent's fontmiddle— aligns the middle of the element with the baseline plus half the x-height of the parenttop— aligns the top of the element with the top of the tallest element on the linebottom— aligns the bottom of the element with the bottom of the lowest element on the line
In addition to keywords, vertical-align also accepts length values (e.g., 5px, 0.5em) and percentage values (e.g., 50%), which offset the element relative to the baseline.
Using an invalid value like none causes a W3C validation error and means your intended styling is silently ignored by the browser. This can lead to unexpected layout results that are difficult to debug, especially in table layouts or inline formatting contexts where vertical alignment significantly affects appearance.
Examples
❌ Invalid: using none
<p>
Text with an <imgsrc="icon.png"alt="icon"style="vertical-align: none;"> inline image.
</p>
The validator will report that none is not a valid vertical-align value. The browser ignores the declaration and defaults to baseline.
✅ Fixed: using a valid keyword
If you want the image vertically centered with the text, use middle:
<p>
Text with an <imgsrc="icon.png"alt="icon"style="vertical-align: middle;"> inline image.
</p>
✅ Fixed: resetting to the default
If your intent was to "remove" any vertical alignment, use baseline (the initial value) or simply remove the property:
<p>
Text with an <imgsrc="icon.png"alt="icon"style="vertical-align: baseline;"> inline image.
</p>
❌ Invalid: none in a stylesheet for table cells
<style>
td.reset{
vertical-align: none;
}
</style>
<table>
<tr>
<tdclass="reset">Cell content</td>
</tr>
</table>
✅ Fixed: valid value for table cells
For table cells, the default vertical-align value is middle in most browsers. To explicitly reset it or set a specific alignment:
<style>
td.top-aligned{
vertical-align: top;
}
</style>
<table>
<tr>
<tdclass="top-aligned">Cell content</td>
</tr>
</table>
✅ Fixed: using a length value
You can also use a specific length to offset the element from the baseline:
<p>
Text with a <spanstyle="vertical-align:4px;">slightly raised</span> word.
</p>
Choose the value that matches your design intent — baseline to reset, middle or top for common alignment needs, or a specific length or percentage for precise control.
An invalid value was assigned to the CSS visibility property inside your HTML document.
The visibility property controls whether an element is visually displayed without affecting the document layout. Unlike display: none, a hidden element still occupies space on the page.
The accepted values for visibility are:
visible— the element is shown (default).hidden— the element is invisible but still takes up space.collapse— used primarily with table rows and columns to remove them without affecting the table layout. On non-table elements, it behaves likehidden.
This error typically occurs when you use a value meant for a different property, such as none (which belongs to display), or a misspelled value like hiden or visble.
Invalid Example
<pstyle="visibility: none;">This text is hidden.</p>
The value none is not valid for visibility. You likely meant hidden or intended to use the display property instead.
Fixed Example
Using the correct visibility value:
<pstyle="visibility: hidden;">This text is hidden but still takes up space.</p>
Or, if you want the element to be fully removed from the layout, use display instead:
<pstyle="display: none;">This text is completely removed from the layout.</p>
The white-space property is a shorthand that combines the behavior of white-space-collapse and text-wrap-mode. When you use a value that doesn't match any of the accepted keywords — whether due to a typo, a made-up value, or a value that belongs to a different CSS property — the W3C validator flags it as invalid. This commonly happens when authors confuse values from related properties (like using break-spaces where it isn't supported in inline styles being validated, or misspelling nowrap as no-wrap).
Using invalid CSS values means browsers will ignore the declaration entirely, falling back to the default behavior (white-space: normal). This can cause unexpected text wrapping or whitespace collapsing that breaks your layout. Keeping your CSS valid ensures consistent rendering across browsers and makes your stylesheets easier to maintain and debug.
The accepted values for white-space are:
normal— Collapses whitespace sequences, wraps text as needed (default).nowrap— Collapses whitespace but suppresses line breaks; text won't wrap.pre— Preserves whitespace and line breaks exactly as written, like the<pre>element.pre-wrap— Preserves whitespace and line breaks, but also allows text to wrap when necessary.pre-line— Collapses whitespace sequences into a single space, but preserves explicit line breaks and allows wrapping.break-spaces— Similar topre-wrap, but trailing spaces and spaces at the end of lines don't hang and do affect box sizing.
Additionally, CSS Text Level 4 introduced shorthand combinations using white-space-collapse and text-wrap-mode keywords, such as collapse, preserve, wrap, and preserve nowrap. However, support for these newer shorthand forms varies, and older validators or browsers may not recognize them.
Global CSS values (inherit, initial, revert, revert-layer, unset) are also valid.
Examples
Incorrect: invalid value triggers the error
A common mistake is using no-wrap (with a hyphen) instead of the correct nowrap:
<pstyle="white-space: no-wrap;">This text should not wrap.</p>
Another common mistake is using a value from a different property entirely:
<pstyle="white-space: hidden;">This text has an invalid white-space value.</p>
Correct: using valid white-space values
<pstyle="white-space: nowrap;">This text will not wrap to a new line.</p>
<pstyle="white-space: pre-wrap;">This text preserves whitespace
and line breaks, but also wraps when needed.</p>
<pstyle="white-space: pre-line;">This collapses extra spaces
but preserves explicit line breaks.</p>
Correct: using the property in a <style> block
<!DOCTYPE html>
<htmllang="en">
<head>
<title>White-space example</title>
<style>
.no-wrap{
white-space: nowrap;
}
.preserve{
white-space: pre-wrap;
}
</style>
</head>
<body>
<pclass="no-wrap">This long paragraph will stay on a single line without wrapping.</p>
<pclass="preserve">This preserves multiple spaces
and line breaks exactly as written.</p>
</body>
</html>
If you encounter this validation error, double-check your white-space value for typos and confirm it matches one of the recognized keywords listed above.
This error originates from CSS validation, not HTML element validation. It typically appears when the validator encounters a width value in a style attribute or <style> block that doesn't conform to the CSS specification for the width property. The CSS width property accepts <length>, <percentage>, auto, min-content, max-content, fit-content, or fit-content(<length-percentage>) values. Anything outside these types—or an expression that produces an incompatible type—will trigger this error.
Common causes include:
- Missing units on a numeric value. In CSS,
width: 400is invalid (unlike the HTMLwidthattribute on elements like<img>, which expects a unitless integer). CSS requires a unit such aspx,em,rem,%,vw, etc., unless the value is0. - Invalid
calc()expressions. For example,calc(100% - 20)is invalid because100%is a percentage and20has no unit—you cannot subtract a unitless number from a percentage. It should becalc(100% - 20px). - Typos or unrecognized values. Things like
width: 50 px(space between number and unit),width: autopx, orwidth: 100pixelsare not valid CSS. - Using HTML attribute syntax in CSS. Writing
width: 400in a stylesheet because you're used to writing<img width="400">in HTML.
This matters for standards compliance and cross-browser reliability. While some browsers may attempt to interpret invalid values, the behavior is undefined and inconsistent. Relying on invalid CSS can lead to broken layouts in certain browsers or future browser versions.
How to Fix It
- Add proper units to any bare numeric
widthvalue in your CSS. Usepx,em,rem,%,vw, or another valid CSS length unit. - Check
calc()expressions to ensure both sides of addition or subtraction are compatible types (e.g., length with length, or percentage with length—both are valid incalc()). Unitless numbers (other than0) cannot be mixed with lengths or percentages in addition/subtraction. - Remove spaces between numbers and their units.
50pxis valid;50 pxis not. - Use valid keywords only:
auto,min-content,max-content,fit-content.
Examples
Incorrect: Missing unit in inline style
<divstyle="width:400;">Content</div>
Correct: Adding a proper unit
<divstyle="width:400px;">Content</div>
Incorrect: Incompatible types in calc()
<divstyle="width:calc(100%-20);">Content</div>
The value 20 has no unit, so it cannot be subtracted from a percentage.
Correct: Compatible types in calc()
<divstyle="width:calc(100%-20px);">Content</div>
Incorrect: Space between number and unit
<pstyle="width:50 %;">Some text</p>
Correct: No space between number and unit
<pstyle="width:50%;">Some text</p>
Incorrect: Unitless number in a <style> block
<!DOCTYPE html>
<htmllang="en">
<head>
<title>Example</title>
<style>
.sidebar{
width:300;
}
</style>
</head>
<body>
<asideclass="sidebar">Sidebar content</aside>
</body>
</html>
Correct: Valid length value in a <style> block
<!DOCTYPE html>
<htmllang="en">
<head>
<title>Example</title>
<style>
.sidebar{
width:300px;
}
</style>
</head>
<body>
<asideclass="sidebar">Sidebar content</aside>
</body>
</html>
Note on the HTML width attribute
Don't confuse CSS width with the HTML width attribute. The HTML width attribute on elements like <img>, <video>, and <canvas> expects a unitless integer:
<imgsrc="photo.jpg"width="400"alt="A sample photo">
Writing width="400px" in an HTML attribute is a separate validation error. The CSS error discussed in this guide specifically concerns width values in stylesheets or style attributes where a valid CSS length is required.
The CSS width property sets an element's width and accepts a single value. The W3C validator reports this error when it encounters something it cannot parse as a valid width declaration. Common causes include:
- Missing units: Writing
width: 300instead ofwidth: 300px. CSS requires explicit units for non-zero lengths. - Multiple values: Writing
width: 100px 200pxas ifwidthaccepted shorthand-style multiple values (it doesn't). - Typos or invalid keywords: Writing
width: auotinstead ofwidth: auto, or using a made-up keyword. - Invalid functions or syntax: Using incorrect function syntax like
width: calc(100% - 20px)with missing spaces around operators, or using browser-prefixed values without a standard fallback. - Unsupported values: Using newer CSS values like
fit-contentormax-contentin a context where the validator's CSS level doesn't recognize them.
This matters because invalid CSS can cause browsers to silently discard the entire declaration, meaning your intended layout won't be applied. Different browsers may handle invalid values differently, leading to inconsistent rendering. Keeping your CSS valid ensures predictable, cross-browser behavior.
Valid values for width
The width property accepts exactly one of the following:
- Length values: A number with a unit, such as
300px,25em,10rem,5vw. - Percentage values: A percentage relative to the containing block, such as
75%. - Keyword values:
auto,max-content,min-content,fit-content. - Function values:
fit-content(20em),calc(100% - 40px),min(300px, 100%),max(200px, 50%),clamp(200px, 50%, 600px). - Global values:
inherit,initial,revert,revert-layer,unset.
Note that 0 is the only numeric value that does not require a unit.
Examples
Incorrect: missing unit
<style>
.box{
width:300;
}
</style>
<divclass="box">Content</div>
A bare number (other than 0) is not valid. The browser won't know if you mean pixels, ems, or something else.
Correct: unit provided
<style>
.box{
width:300px;
}
</style>
<divclass="box">Content</div>
Incorrect: too many values
<style>
.sidebar{
width:200px400px;
}
</style>
<asideclass="sidebar">Sidebar</aside>
Unlike properties such as margin or padding, width only accepts a single value.
Correct: single value
<style>
.sidebar{
width:200px;
}
</style>
<asideclass="sidebar">Sidebar</aside>
Incorrect: typo in keyword
<style>
.container{
width: auot;
}
</style>
<divclass="container">Content</div>
Correct: proper keyword
<style>
.container{
width: auto;
}
</style>
<divclass="container">Content</div>
Incorrect: malformed calc() expression
<style>
.panel{
width:calc(100%-40px);
}
</style>
<divclass="panel">Content</div>
The calc() function requires spaces around + and - operators.
Correct: properly spaced calc() expression
<style>
.panel{
width:calc(100%-40px);
}
</style>
<divclass="panel">Content</div>
Incorrect: accidental semicolon or extra text
<style>
.card{
width:50% important;
}
</style>
<divclass="card">Content</div>
If you intended to use !important, the ! is required.
Correct: proper !important syntax
<style>
.card{
width:50%!important;
}
</style>
<divclass="card">Content</div>
The CSS width property contains an invalid value.
The width property accepts specific types of values: lengths (like 100px, 10em, 5rem), percentages (50%), viewport units (100vw), the keyword auto, and sizing keywords like max-content, min-content, or fit-content. The validator rejects anything that doesn't match these formats.
Common mistakes that trigger this error:
- Missing a unit:
width: 100instead ofwidth: 100px. Plain numbers (other than0) are not valid CSS lengths. - Using an invalid unit or typo:
width: 100 px(with a space),width: 100ppx. - Passing a non-length value:
width: red,width: bold,width: none. The keywordnoneworks formax-widthbut not forwidth. - Including extra characters:
width: 100px;50pxorwidth: 100px !importnt.
Invalid example
<divstyle="width: 600">
<p>This box has no unit on its width value.</p>
</div>
The value 600 is not valid because it lacks a CSS unit.
Fixed example
<divstyle="width: 600px">
<p>This box now has a valid width.</p>
</div>
Adding px (or another appropriate unit like em, %, rem, vw) makes the value valid. If the intent is to let the element size itself naturally, use width: auto instead.
This is an internal error from the W3C validator's CSS checking engine (the Jigsaw CSS validator). The message Cannot invoke "org.w3c.css.values.CssValue.getType()" because "Y" is null is a Java NullPointerException surfacing from the validator's source code. In practical terms, it means the validator tried to determine the type of a CSS value, but that value didn't exist or couldn't be computed.
There are several common causes for this error:
- Malformed or incomplete CSS values — A property is missing part of its value, such as a shorthand with too few components, or a function with missing arguments.
- Unsupported CSS features — Newer CSS features or non-standard syntax that the validator's CSS engine doesn't fully support can trigger internal failures rather than clean error messages.
- Invalid value combinations — Using values together in a way that doesn't match any known CSS grammar rule can cause the parser to fail unexpectedly.
- Syntax errors in custom properties or functions — Mistakes inside
calc(),var(), or other CSS functions can sometimes cause this kind of crash in the validator.
While this error technically originates from the validator itself (and could be considered a validator bug), it almost always points to CSS that is non-standard, malformed, or pushing the boundaries of what the validator can parse. Fixing the underlying CSS issue resolves the error.
How to Fix It
- Locate the CSS property referenced in the error — The
"X"in the error message identifies the CSS property or value that caused the failure. - Check for syntax errors — Look for missing values, unclosed parentheses, stray commas, or incomplete shorthand declarations.
- Simplify complex expressions — If you're using
calc(), nested functions, or complex shorthand values, try breaking them into simpler, longhand declarations. - Check for unsupported features — Some modern CSS (e.g., certain uses of
color-mix(), newer color syntaxes, or container query units) may not yet be supported by the validator. Consider whether validation of that specific rule is critical. - Validate CSS separately — Paste your CSS into the W3C CSS Validator directly to isolate the problematic rule.
Examples
Malformed shorthand value
A missing value in a shorthand property can trigger this internal error:
<divstyle="border:1px solid;">Content</div>
The border shorthand here has a trailing space after solid with no color specified. While browsers handle this gracefully by using a default, the validator may fail to process the incomplete value. Fix it by providing all intended values explicitly:
<divstyle="border:1px solid black;">Content</div>
Incomplete function syntax
Missing arguments inside CSS functions are another common trigger:
<style>
.box{
width:calc(100%-);
background-color:rgb(255,128);
}
</style>
The calc() expression is missing its second operand, and rgb() is missing its third argument. Fix both by providing complete values:
<style>
.box{
width:calc(100%-20px);
background-color:rgb(255,128,0);
}
</style>
Complex expressions the validator cannot parse
Sometimes valid, modern CSS triggers this error because the validator's engine doesn't fully support it:
<style>
.card{
background:color-mix(in srgb,#3498db70%, transparent);
}
</style>
If this triggers the internal error, you can provide a fallback or simplify:
<style>
.card{
background:rgba(52,152,219,0.7);
}
</style>
Accidental double values
A typo that results in two values where one is expected can also cause this:
<style>
.text{
font-size:16px14px;
}
</style>
Fix by providing only the single expected value:
<style>
.text{
font-size:16px;
}
</style>
If you believe your CSS is correct and the validator is producing this error incorrectly, it may be a genuine bug in the validator. You can report it at the W3C CSS Validator's GitHub repository. In the meantime, check that your CSS works correctly across target browsers and consider adding a /* validated */ comment near the line so you can track intentional exceptions.
CSS uses semicolons as delimiters between declarations. When you forget one, the parser tries to interpret the next property name as part of the previous declaration's value. For example, if you write z-index: auto content: "", the parser reads auto content as if it were the value of z-index, which is invalid. It then encounters the colon after what it expected to be a value, resulting in a parsing error that can cause one or more of your declarations to be silently ignored.
This is a problem for several reasons:
- Broken styles: The browser will typically discard the malformed declaration and potentially subsequent ones, leading to unexpected visual results that can be difficult to debug.
- Standards compliance: The CSS specification requires semicolons between declarations. While the last declaration in a block technically doesn't need a trailing semicolon, omitting it is a common source of bugs when new declarations are added later.
- Maintainability: Always including semicolons — even on the last declaration — is a widely recommended best practice. It prevents this exact class of errors when code is edited or rearranged in the future.
To fix this issue, locate the line referenced in the error message and check the declaration immediately before it. Add the missing semicolon at the end of that declaration.
Examples
❌ Missing semicolon between declarations
The semicolon is missing after z-index: auto, so the parser cannot recognize content as a new property:
<style>
.overlay{
z-index: auto
content: "";
display: block;
}
</style>
✅ Fixed with semicolon added
Adding the semicolon after auto properly terminates the z-index declaration:
<style>
.overlay{
z-index: auto;
content:"";
display: block;
}
</style>
❌ Missing semicolon with shorthand properties
Shorthand values with multiple parts can make it harder to spot the missing semicolon:
<style>
.card{
margin:10px20px10px20px
padding: 1em;
border:1px solid #ccc;
}
</style>
✅ Fixed shorthand example
<style>
.card{
margin:10px20px10px20px;
padding:1em;
border:1px solid #ccc;
}
</style>
❌ Missing semicolon on the last declaration causes issues when editing
While technically valid, omitting the trailing semicolon on the last declaration becomes a bug the moment a new line is added:
<style>
.button{
color: white;
background: blue
border-radius: 4px;
}
</style>
Here, background: blue was originally the last declaration (without a semicolon). When border-radius was added afterward, the missing semicolon was not noticed.
✅ Best practice: always include a trailing semicolon
<style>
.button{
color: white;
background: blue;
border-radius:4px;
}
</style>
By consistently ending every declaration with a semicolon — including the last one in each rule block — you avoid this error entirely and make your stylesheets easier to maintain.
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 writecalc(10px * 3)orcalc(3 * 10px), but notcalc(10px * 5px). - Division (
/): The right-hand operand must be a plain<number>(unitless and non-zero). You can writecalc(100px / 2), but notcalc(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 -->
<divstyle="width:calc(100%-);"></div>
<!-- ✅ Fixed: both operands are present -->
<divstyle="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 -->
<divstyle="width:calc(10px*5px);"></div>
<!-- ✅ Fixed: one operand is a unitless number -->
<divstyle="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 -->
<divstyle="height:calc(500px/2em);"></div>
<!-- ✅ Fixed: divisor is a unitless number -->
<divstyle="height:calc(500px/2);"></div>
Nested calc() with a missing value
Errors can hide inside nested expressions:
<!-- ❌ Wrong: inner calc has an incomplete expression -->
<pstyle="margin-top:calc(2rem+calc(100%*));"></p>
<!-- ✅ Fixed: all operands are present and valid -->
<pstyle="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() -->
<divstyle="width:calc(auto *2);"></div>
<!-- ✅ Fixed: use a numeric value or percentage -->
<divstyle="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.
When the W3C HTML Validator checks your document, it also validates any inline styles (in style attributes) and embedded stylesheets (in <style> elements). A CSS parse error occurs when the parser encounters something it cannot interpret according to CSS specifications. The "X" in the error message refers to the specific property, value, or token that triggered the failure.
Understanding CSS Parse Errors
CSS parse errors can stem from many different causes:
- Typos in property names or values — e.g.,
colrinstead ofcolor, or10xpinstead of10px. - Missing or extra punctuation — a forgotten semicolon, an extra colon, unmatched braces or parentheses.
- Invalid values for a property — using a value that doesn't belong to that property's grammar.
- Vendor-prefixed or non-standard syntax — properties like
-webkit-appearanceor-moz-osx-font-smoothingare not part of the CSS standard and will trigger parse errors in the validator. - Modern CSS features not yet recognized — some newer CSS syntax may not be supported by the validator's parser yet.
- Stray characters or encoding issues — invisible characters, smart quotes, or copy-paste artifacts from word processors.
While browsers are generally forgiving and will skip CSS they don't understand, parse errors can indicate real bugs that cause styles to silently fail. Fixing them ensures your CSS is standards-compliant and behaves predictably across all browsers.
Common Causes and Fixes
Typos and syntax mistakes
The most frequent cause is a simple typo or a missing character. Always double-check the exact line the validator points to.
Missing semicolons
A forgotten semicolon between declarations can cause the parser to misinterpret subsequent properties.
Invalid or malformed values
Using values that don't match the property's expected syntax — such as omitting units, using incorrect function syntax, or providing the wrong number of arguments — will trigger parse errors.
Vendor prefixes
The W3C validator checks against the CSS specification. Vendor-prefixed properties and values are non-standard and will produce parse errors. While you may still need them in production, be aware that these will always flag in validation.
Examples
❌ Missing semicolon between declarations
<pstyle="color: red background-color: blue;">Hello</p>
The missing semicolon after red causes the parser to try to interpret red background-color: blue as a single value, resulting in a parse error.
✅ Fixed: semicolons separating declarations
<pstyle="color: red;background-color: blue;">Hello</p>
❌ Typo in property name
<style>
.box{
widht:100px;
hieght:200px;
}
</style>
✅ Fixed: correct property names
<style>
.box{
width:100px;
height:200px;
}
</style>
❌ Missing unit on a value
<style>
.container{
margin:10;
padding:20px;
}
</style>
Numeric values (other than 0) require a unit. The value 10 without a unit like px, em, or rem is invalid.
✅ Fixed: unit included
<style>
.container{
margin:10px;
padding:20px;
}
</style>
❌ Extra or misplaced characters
<style>
.title{
font-size:: 16px;
color:#3333;
}
</style>
The double colon after font-size and the 4-digit hex color #3333 (which is valid in CSS Color Level 4 but may not be recognized by all validator parsers) can trigger errors.
✅ Fixed: correct syntax
<style>
.title{
font-size:16px;
color:#333333;
}
</style>
❌ Unmatched parentheses in a function
<style>
.overlay{
background: rgba(0,0,0,0.5;
}
</style>
✅ Fixed: closing parenthesis added
<style>
.overlay{
background:rgba(0,0,0,0.5);
}
</style>
Tips for Debugging Parse Errors
- Read the error message carefully. The validator usually points to the specific token or line that caused the failure.
- Validate CSS separately. Use the W3C CSS Validation Service for more detailed CSS-specific error messages.
- Check for invisible characters. If you copied CSS from a word processor, PDF, or website, hidden characters like zero-width spaces or smart quotes (
"instead of") may be present. Retype the line manually if in doubt. - Simplify and isolate. If you can't find the error, remove declarations one at a time until the error disappears, then inspect the last removed declaration closely.
The validator flags any declaration where the property token doesn’t match a known CSS property in its ruleset. Common causes include typos, wrong hyphenation, using values where property names should go, properties from older drafts that were renamed, or relying solely on vendor-prefixed/experimental properties without a standard equivalent. It can also show up when copy-pasting snippets that include custom, nonstandard properties.
Why this matters:
- Browser compatibility: Unknown properties are ignored, causing styles to silently fail.
- Maintainability: Typos and nonstandard syntax make CSS harder to debug.
- Standards compliance: Clean, validated CSS reduces cross-browser surprises and eases future maintenance.
How to fix it:
- Check spelling and hyphenation exactly (e.g.,
text-decoration-skip-ink, nottext-decoration-skipink). - Verify the property exists on MDN or in the CSS specifications; if it’s not documented, it’s likely invalid.
- Replace deprecated or draft names with current standardized ones.
- If using experimental features, include a standard fallback and keep vendor-prefixed versions alongside the unprefixed property when supported.
- Remove framework- or tool-specific tokens that aren’t valid CSS at runtime.
- Don’t invent properties. If you need custom data for JS, use
data-*attributes in HTML, not fake CSS properties.
Examples
Example that triggers the error (typo) and the corrected version
Invalid:
<pstyle="colr: red;">Hello</p>
Valid:
<pstyle="color: red;">Hello</p>
Example using a deprecated/draft name replaced with the current property
Invalid (older draft name):
<divstyle="gap:1rem;grid-row-gap:8px;"></div>
Valid (current, standardized property):
<divstyle="row-gap:8px;gap:1rem;"></div>
Example with vendor-prefixed property plus standard fallback
Invalid (only vendor-prefixed, missing standard property):
<divstyle="-webkit-user-select: none;"></div>
Valid (fallback plus prefix):
<divstyle="user-select: none;-webkit-user-select: none;"></div>
Example removing a nonstandard custom property name misuse
Invalid (attempting to invent a property):
<divstyle="button-style: primary;"></div>
Valid (use classes and real CSS properties):
<style>
.btn--primary{
background-color:#0b5fff;
color:#fff;
}
</style>
<buttonclass="btn--primary">Submit</button>
Example with custom properties (variables) used correctly
Valid use of CSS custom properties (won’t trigger the error because the property is standard and custom properties start with --):
<style>
:root{
--brand-color:#0b5fff;
}
.tag{
color:var(--brand-color);
}
</style>
<spanclass="tag">Tag</span>
Full document with corrected properties
<!doctype html>
<htmllang="en">
<head>
<metacharset="utf-8">
<title>CSS Property Validation Fixes</title>
<metaname="viewport"content="width=device-width, initial-scale=1">
<style>
.card{
display: grid;
gap:1rem;
row-gap:0.5rem;
user-select: none;
-webkit-user-select: none;
color:#222;
}
</style>
</head>
<body>
<divclass="card">Valid CSS properties in use</div>
</body>
</html>
Quick checklist:
- Confirm the property on MDN. If not found, it’s probably invalid.
- Fix spelling/casing; CSS properties are lowercase with hyphens.
- Prefer standardized names; keep prefixes only as supplements.
- Use CSS custom properties starting with
--if you need variables. - Remove tool-specific placeholders before validation.
Every CSS property has a defined value syntax that specifies exactly which values it accepts and how many. When the validator encounters a declaration that doesn't match this syntax, it flags the error. This can happen for several distinct reasons:
- Too many values: A property receives more values than its syntax allows. For example,
marginaccepts one to four values, so a fifth value is invalid. Thecolorproperty accepts only a single color value, so writing two colors is an error. - Unrecognized values: A keyword is misspelled (e.g.,
blockyinstead ofblock) or simply doesn't exist for that property (e.g.,color: bold). - Newer or non-standard values: A value that belongs to a draft specification, a vendor-prefixed feature, or a browser-specific extension may not be recognized by the validator.
- Missing separators or syntax errors: A missing comma in a multi-value function like
rgb()or a missing slash in shorthand likefontcan cause the parser to misinterpret the values.
This matters because browsers handle invalid CSS unpredictably — they typically discard the entire declaration, which means your intended styles silently disappear. Fixing these errors ensures your styles are applied consistently across browsers and makes your stylesheets easier to maintain and debug.
How to Fix
- Identify the property and value reported in the error message.
- Check spelling of every keyword. Common mistakes include
inheret(should beinherit),trasparent(should betransparent), andcentre(should becenter). - Count the values and compare against the property's specification. Consult MDN Web Docs for the accepted value syntax.
- Verify function syntax — ensure commas, slashes, and parentheses are correct in functions like
rgb(),calc(), andclamp(). - Check for unsupported modern syntax — if you're using newer CSS features, the validator may not recognize them yet. In that case, verify the syntax is correct per the spec and consider the warning informational.
Examples
Too many values for a property
The color property only accepts a single color value, and margin accepts at most four values:
<!-- ❌ Invalid: too many values -->
<pstyle="color: red blue;">Hello</p>
<pstyle="margin:10px20px5px0px15px;">Hello</p>
<!-- ✅ Valid: correct number of values -->
<pstyle="color: red;">Hello</p>
<pstyle="margin:10px20px5px0px;">Hello</p>
Unrecognized keyword value
A typo or non-existent keyword triggers the error:
<!-- ❌ Invalid: "blocky" is not a valid display value -->
<divstyle="display: blocky;">Content</div>
<!-- ✅ Valid: correct keyword -->
<divstyle="display: block;">Content</div>
Misspelled value in a <style> block
<!-- ❌ Invalid -->
<style>
.box{
background-color: trasparent;
text-align: centre;
}
</style>
<!-- ✅ Valid -->
<style>
.box{
background-color: transparent;
text-align: center;
}
</style>
Incorrect function syntax
Missing commas or extra arguments inside CSS functions can also trigger this error:
<!-- ❌ Invalid: missing commas in rgb() -->
<pstyle="color:rgb(255000.5);">Hello</p>
<!-- ✅ Valid: use the correct modern syntax with a slash for alpha -->
<pstyle="color:rgb(25500/0.5);">Hello</p>
Shorthand property confusion
Shorthand properties like font and background have specific value order requirements. Providing values in the wrong order or mixing incompatible values causes errors:
<!-- ❌ Invalid: incorrect font shorthand -->
<style>
p{
font: bold Arial 16px;
}
</style>
<!-- ✅ Valid: size must come before family, weight before size -->
<style>
p{
font: bold 16px Arial;
}
</style>
When in doubt, break shorthand properties into their individual longhand properties (font-weight, font-size, font-family) to isolate which value the validator is rejecting.
In CSS, a "dimension" is a number immediately followed by a unit identifier — for example, 16px, 2em, or 100vh. When the validator encounters a dimension token with a unit it doesn't recognize, it flags it as an unknown dimension. The "X" in the error message is replaced with the actual unrecognized value, such as 10quux or 5pixels.
This issue commonly arises from:
- Typos in unit names — writing
10pxlinstead of10px, or2emsinstead of2em. - Made-up or non-standard units — using units that don't exist in any CSS specification.
- Missing spaces or operators — accidentally concatenating a number with a keyword, like
100vhmaxinstead of usingmax(100vh, ...). - Using units in the wrong context — some newer or less common units may not yet be recognized by the validator, though all widely supported CSS units should be accepted.
This matters because browsers may silently ignore or misinterpret properties with invalid dimension values, leading to broken layouts. Using valid units ensures consistent rendering across browsers and compliance with CSS standards.
How to Fix
- Check the CSS value flagged in the error message.
- Verify the unit is a valid CSS unit (e.g.,
px,em,rem,%,vw,vh,vmin,vmax,ch,ex,cm,mm,in,pt,pc,s,ms,deg,rad,turn,fr). - Fix any typos, remove extra characters, or replace non-standard units with valid ones.
- If the value is meant to be unitless (like
line-height: 1.5), remove the erroneous unit entirely.
Examples
Incorrect: Misspelled unit
<divstyle="margin:10pxl;">Hello</div>
The unit pxl is not a valid CSS unit. The validator reports an unknown dimension for 10pxl.
Correct: Valid unit
<divstyle="margin:10px;">Hello</div>
Incorrect: Made-up unit
<style>
.box{
width:50pixels;
height:200hv;
}
</style>
Neither pixels nor hv are valid CSS units.
Correct: Standard CSS units
<style>
.box{
width:50px;
height:200vh;
}
</style>
Incorrect: Missing space causes concatenation
<style>
.container{
font-size:1remx;
}
</style>
The extra x turns rem into the unknown dimension remx.
Correct: Proper unit
<style>
.container{
font-size:1rem;
}
</style>
Incorrect: Unit where none is needed
<style>
p{
line-height:1.5em2;
}
</style>
Correct: Unitless value or valid unit
<style>
p{
line-height:1.5;
}
</style>
If you're confident the unit is valid and part of a newer CSS specification (such as container query units like cqi or cqb), the validator may not yet support it. In that case, the warning can be noted but may not indicate an actual problem in modern browsers. However, always double-check for typos first — the most common cause is simply a misspelled unit.
Private Use Area (PUA) characters are reserved ranges in Unicode whose interpretation is not specified by any encoding standard. Their meaning is determined entirely by private agreement between cooperating parties—such as a font vendor and its users. This means that a PUA character that renders as a custom icon in one font may appear as a blank square, a question mark, or a completely different glyph when that specific font is unavailable.
This warning commonly appears when using icon fonts like older versions of Font Awesome, Material Icons, or custom symbol fonts. These fonts map their icons to PUA code points. While this approach works visually when the font loads correctly, it creates several problems:
- Accessibility: Screen readers cannot interpret PUA characters meaningfully. A visually impaired user may hear nothing, hear "private use area character," or hear an unrelated description depending on their assistive technology.
- Portability: If the associated font fails to load (due to network issues, content security policies, or user preferences), the characters become meaningless boxes or blank spaces.
- Interoperability: Copy-pasting text containing PUA characters into another application, email client, or document will likely produce garbled or missing content since the receiving system won't know how to interpret those code points.
- Standards compliance: The W3C and Unicode Consortium both recommend against using PUA characters in publicly exchanged documents for exactly these reasons.
Sometimes PUA characters sneak into your HTML unintentionally—through copy-pasting from word processors, PDFs, or design tools that use custom encodings. Other times, they are inserted deliberately via CSS content properties or HTML entities by icon font libraries.
To fix this, identify where the PUA characters appear and replace them with standard alternatives. Use inline SVG for icons, standard Unicode symbols where appropriate (e.g., ✓ U+2713 instead of a PUA checkmark), or CSS background images. If you must use an icon font, hide the PUA character from assistive technology using aria-hidden="true" and provide an accessible label separately.
Examples
Problematic: PUA character used directly in HTML
<!-- The character below (U+E001) is a PUA code point -->
<p>Status: </p>
Without the specific icon font loaded, PUA characters like U+E001 render as missing glyphs or blank spaces.
Fixed: Using inline SVG with accessible label
<p>
Status:
<svgaria-hidden="true"width="16"height="16"viewBox="0 0 16 16">
<pathd="M6 10.8L2.5 7.3 1.1 8.7 6 13.6 14.9 4.7 13.5 3.3z"/>
</svg>
<span>Complete</span>
</p>
Problematic: Icon font via CSS content property
<style>
.icon-check::before{
font-family:"MyIcons";
content:"\e001";/* PUA character */
}
</style>
<spanclass="icon-check"></span>
Fixed: Icon font with accessibility safeguards
If you must continue using an icon font, hide the PUA character from assistive technology and provide an accessible alternative:
<style>
.icon-check::before{
font-family:"MyIcons";
content:"\e001";
}
</style>
<spanclass="icon-check"aria-hidden="true"></span>
<spanclass="sr-only">Checkmark</span>
Note that this approach still triggers the validator warning if the PUA character is detectable in the markup. The most robust fix is to avoid PUA characters entirely.
Fixed: Using a standard Unicode character
<p>Status: ✓ Complete</p>
The character ✓ (U+2713, CHECK MARK) is a standard Unicode character that is universally understood and renders consistently across platforms.
Problematic: PUA character from copy-paste
<p>Click here to download</p>
Invisible or unexpected PUA characters sometimes hide in text pasted from external sources. Inspect your source code carefully—many code editors can highlight non-ASCII characters or reveal their code points.
Fixed: Cleaned-up text
<p>Click here to download</p>
If you've audited your document and determined that the PUA characters are intentional and rendering correctly in your target environments, you may choose to accept this warning. However, for publicly accessible web pages, replacing PUA characters with standard alternatives is always the safer and more accessible choice.
When an HTML element contains the same attribute more than once, the browser must decide which value to use. According to the WHATWG HTML specification, the parser keeps only the first occurrence and silently discards the rest. This means any values you placed in the second (or subsequent) attribute are completely ignored — often leading to unexpected behavior that can be difficult to debug.
This issue commonly arises in a few scenarios:
- Copy-paste mistakes where code fragments are merged without deduplicating attributes.
- Template or CMS output where multiple systems each inject the same attribute onto an element.
- Attempting to assign multiple values by repeating the attribute instead of combining the values into one (especially common with
classandstyle).
Why this matters
- Unpredictable behavior: Since only the first value is kept, the duplicate is silently dropped. If you intended the second value, your page won't work as expected and there will be no visible error in the browser console.
- Accessibility concerns: Duplicate
idattributes or duplicate ARIA attributes can confuse assistive technologies, breaking navigation and screen reader announcements. - Standards compliance: Duplicate attributes violate the HTML specification and will cause validation errors, which can signal deeper quality issues in your markup.
- Maintainability: Code with duplicate attributes is harder to read and maintain, and it obscures the developer's intent.
Examples
❌ Duplicate class attribute
A common mistake is trying to add multiple classes by repeating the class attribute:
<divclass="card"class="highlighted">Content</div>
The browser only applies "card" and ignores "highlighted" entirely.
✅ Merge classes into a single attribute
Combine all class names into one space-separated class attribute:
<divclass="card highlighted">Content</div>
❌ Duplicate id attribute
<aid="home-link"id="nav-link">Home</a>
Only "home-link" is used; "nav-link" is discarded.
✅ Use a single id
Choose the appropriate id value. If you need multiple hooks for styling or scripting, use class for the additional identifier:
<aid="home-link"class="nav-link">Home</a>
❌ Duplicate style attribute
<pstyle="color: red;"style="font-weight: bold;">Important text</p>
Only color: red is applied; the bold style is lost.
✅ Combine styles into one attribute
<pstyle="color: red;font-weight: bold;">Important text</p>
❌ Duplicate data-* or event attributes
This also applies to data attributes and event handlers:
<buttondata-action="save"data-action="submit"onclick="handleClick()"onclick="trackEvent()">
Submit
</button>
✅ Use a single value per attribute
<buttondata-action="submit"onclick="handleClick();trackEvent();">
Submit
</button>
❌ Duplicate attributes in template output
Templating systems sometimes produce duplicate attributes when multiple directives target the same element:
<inputtype="text"name="email"placeholder="Enter email"placeholder="you@example.com">
✅ Ensure templates produce a single attribute
Review your template logic so only one value is rendered:
<inputtype="text"name="email"placeholder="you@example.com">
How to fix it
- Search your markup for the attribute name flagged by the validator. Look for it appearing more than once on the same element.
- Decide which value is correct. If both values are needed, merge them into a single attribute (e.g., space-separated class names, semicolon-separated style declarations).
- Remove the duplicate. Delete the extra occurrence so only one remains.
- Check your build tools and templates. If the duplication comes from a CMS, templating engine, or JavaScript that sets attributes dynamically, fix the source rather than just the output.
- Re-validate your page to confirm the error is resolved.
The id attribute serves as a unique identifier for a single element in the DOM. The HTML specification explicitly requires that id values be unique across the entire document. When you reuse an id, you violate this contract, and the consequences can be subtle but far-reaching.
JavaScript behavior becomes unpredictable. Methods like document.getElementById() will only return the first element with a given id, silently ignoring any duplicates. This can cause scripts to target the wrong element or fail to interact with elements you expect them to reach.
CSS selectors may not apply as intended. While most browsers will style all elements with a duplicated id, this behavior is not guaranteed by the specification and can lead to inconsistencies across browsers.
Accessibility is compromised. Screen readers and other assistive technologies rely on unique IDs to associate labels with form controls (via for/id pairing), link aria-describedby or aria-labelledby references to specific elements, and navigate fragment identifiers (anchor links). Duplicate IDs break these associations, potentially making content confusing or unusable for people relying on assistive technology.
Fragment navigation breaks. When a URL contains a hash like #section-intro, the browser scrolls to the element with that id. If multiple elements share the same id, only the first one will be targeted, which may not be the intended destination.
Common causes of duplicate IDs include copy-pasting HTML blocks without updating the id values, dynamically generating content in a loop without appending a unique suffix, and reusing template partials that contain hardcoded id attributes.
To fix this issue, audit your document for repeated id values. If multiple elements need the same identifier for styling purposes, use the class attribute instead. If the id is needed for JavaScript or ARIA references, make each value unique — for example, by appending a number or descriptive suffix.
Examples
❌ Duplicate IDs on multiple elements
<divid="card">
<h2>First Card</h2>
</div>
<divid="card">
<h2>Second Card</h2>
</div>
Both <div> elements share id="card", which triggers the validation error.
✅ Use unique IDs
<divid="card-1">
<h2>First Card</h2>
</div>
<divid="card-2">
<h2>Second Card</h2>
</div>
✅ Use class instead when you don't need unique identification
<divclass="card">
<h2>First Card</h2>
</div>
<divclass="card">
<h2>Second Card</h2>
</div>
❌ Duplicate IDs break label associations
<labelfor="email">Work Email</label>
<inputtype="email"id="email"name="work_email">
<labelfor="email">Personal Email</label>
<inputtype="email"id="email"name="personal_email">
Both inputs share id="email", so the second <label> will incorrectly point to the first input. A screen reader user clicking "Personal Email" would be focused on the wrong field.
✅ Unique IDs for each label–input pair
<labelfor="work-email">Work Email</label>
<inputtype="email"id="work-email"name="work_email">
<labelfor="personal-email">Personal Email</label>
<inputtype="email"id="personal-email"name="personal_email">
❌ Duplicate IDs in dynamically repeated content
This often happens when generating HTML in a loop or reusing a template:
<sectionid="product">
<h2>Widget A</h2>
</section>
<sectionid="product">
<h2>Widget B</h2>
</section>
<sectionid="product">
<h2>Widget C</h2>
</section>
✅ Append a unique suffix
<sectionid="product-1">
<h2>Widget A</h2>
</section>
<sectionid="product-2">
<h2>Widget B</h2>
</section>
<sectionid="product-3">
<h2>Widget C</h2>
</section>
If no element actually needs to be uniquely identified, remove the id entirely and use a class or a data attribute instead.
The <a> element has an implicit ARIA role of link (when it has an href) or generic (when it doesn't). Certain ARIA state attributes, like aria-checked, are only valid on elements with specific roles that support them. For instance, aria-checked is designed for roles like checkbox, menuitemcheckbox, radio, switch, or option. If you place aria-checked on an <a> element without assigning one of these compatible roles, the validator raises this error because the attribute doesn't make sense in the context of the element's current role.
This matters for several reasons. Screen readers and other assistive technologies rely on the relationship between roles and their supported states to convey meaningful information to users. An aria-checked attribute on a plain link creates a confusing experience — the user hears that something is "checked" but the element is announced as a link, which isn't a concept that supports checked/unchecked states. This mismatch can make interfaces unusable for people relying on assistive technology.
To fix this issue, you need to either:
- Add an appropriate
rolethat supports the ARIA state attribute you're using. - Use a more semantically appropriate element, such as
<input type="checkbox">or<button>, which natively supports the concept of being checked or toggled. - Remove the unsupported ARIA attribute if it doesn't actually reflect the element's behavior.
Examples
Incorrect: aria-checked without a compatible role
This triggers the validation error because <a> doesn't support aria-checked without an explicit role:
<ahref="#"aria-checked="true">Dark mode</a>
Fixed: Adding a compatible role
Adding role="menuitemcheckbox" (within a menu context) or role="switch" makes aria-checked valid:
<ulrole="menu">
<lirole="none">
<ahref="#"role="menuitemcheckbox"aria-checked="true">Show notifications</a>
</li>
<lirole="none">
<ahref="#"role="menuitemcheckbox"aria-checked="false">Dark mode</a>
</li>
</ul>
Fixed: Using a <button> with role="switch" instead
In many cases, a <button> is a better semantic fit than an <a> for toggle-like interactions:
<buttonrole="switch"aria-checked="true">Dark mode</button>
Correct: Tab list using <a> elements with proper roles
When building a tab interface with anchor elements, each tab needs role="tab" along with supporting attributes like aria-selected:
<divclass="tab-interface">
<divrole="tablist"aria-label="Settings">
<arole="tab"href="#panel-1"aria-selected="true"aria-controls="panel-1"id="tab-1">
General
</a>
<arole="tab"href="#panel-2"aria-selected="false"aria-controls="panel-2"id="tab-2"tabindex="-1">
Advanced
</a>
</div>
<divid="panel-1"role="tabpanel"tabindex="0"aria-labelledby="tab-1">
<p>General settings content</p>
</div>
<divid="panel-2"role="tabpanel"tabindex="0"aria-labelledby="tab-2"hidden>
<p>Advanced settings content</p>
</div>
</div>
Incorrect: aria-selected on a plain <a> without a role
<ahref="/settings"aria-selected="true">Settings</a>
Fixed: Adding the appropriate role
<ahref="/settings"role="tab"aria-selected="true">Settings</a>
When choosing a fix, always consider whether the <a> element is truly the best choice. If the element doesn't navigate the user to a new URL, a <button> is usually more appropriate. Reserve <a> for actual navigation, and use ARIA roles and states only when they accurately describe the element's behavior in the interface.
According to the HTML specification, the <a> element can exist without an href attribute, but in that case it represents a placeholder where a link might otherwise have been placed. However, the validator flags this as an issue because an <a> element without href and without role is ambiguous — browsers won't treat it as a link (it won't be focusable or keyboard-accessible), and assistive technologies won't know how to present it to users.
This matters for several reasons:
- Accessibility: Without
href, the<a>element loses its implicitrole="link"and is no longer announced as a link by screen readers. It also won't appear in the tab order, making it invisible to keyboard users. - Semantics: If the element is styled and scripted to behave like a button or link but lacks the proper attributes, it creates a disconnect between what users see and what the browser understands.
- Standards compliance: The spec expects you to be explicit about the element's purpose when
hrefis absent.
The most common cause of this issue is using <a> elements as JavaScript-only click targets without providing an href, or using them as styled containers without any interactive purpose.
How to Fix It
There are several approaches depending on your intent:
- Add an
hrefattribute if the element should be a link. This is the most common and recommended fix. - Add a
roleattribute if you're deliberately using<a>withouthreffor a specific purpose, such asrole="button". - Use a different element entirely. If it's not a link, consider using a
<button>,<span>, or another semantically appropriate element.
Examples
❌ Missing both href and role
<a>Click here</a>
This triggers the validator error because the <a> has neither href nor role.
❌ JavaScript-only handler without href
<aonclick="doSomething()">Submit</a>
Even with an event handler, the element lacks href and role, so it fails validation and is inaccessible to keyboard users.
✅ Fix by adding an href
<ahref="/about">About us</a>
Adding href makes it a proper hyperlink — focusable, keyboard-accessible, and recognized by screen readers.
✅ Fix by adding role for a non-link purpose
<arole="button"tabindex="0"onclick="doSomething()">Submit</a>
If you must use <a> without href as a button, add role="button" and tabindex="0" to ensure it's focusable and properly announced. However, consider using a real <button> instead.
✅ Better: use the right element
<buttontype="button"onclick="doSomething()">Submit</button>
If the element triggers an action rather than navigating somewhere, a <button> is the correct semantic choice. It's focusable by default, responds to keyboard events, and doesn't need extra attributes.
✅ Placeholder anchor (intentional non-link)
<arole="link"aria-disabled="true">Coming soon</a>
If you're intentionally showing a placeholder where a link will eventually appear, you can add a role and indicate its disabled state for assistive technologies. Alternatively, use a <span> with appropriate styling to avoid the issue altogether.
Validate at scale.
Ship accessible websites, faster.
Automated HTML & accessibility validation for large sites. Check thousands of pages against WCAG guidelines and W3C standards in minutes, not days.
Pro Trial
Full Pro access. Cancel anytime.
Start Pro Trial →Join teams across 40+ countries