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 transform CSS property lets you rotate, scale, skew, or translate an element by modifying its coordinate space. The W3C validator raises this error when the value assigned to transform doesn't conform to valid CSS syntax. This typically happens when:
- A transform function name is misspelled (e.g.,
rotateZtyped asrotatezin some contexts, orskewtyped asskeew). - Too many arguments are passed to a transform function (e.g.,
rotate(45deg, 20deg)instead ofrotate(45deg)). - Arguments are missing required units (e.g.,
rotate(45)instead ofrotate(45deg)). - Multiple transform functions are separated by commas instead of spaces.
- An invalid or non-existent function name is used (e.g.,
transform: flip()). - Vendor-prefixed values like
-webkit-transformsyntax are used in the standardtransformproperty incorrectly.
This matters for standards compliance because browsers may silently ignore an invalid transform declaration entirely, meaning none of your intended transformations will be applied. Catching these errors during validation helps prevent unexpected layout or visual issues.
Each transform function has a specific signature. For example, rotate() accepts exactly one angle value, translate() accepts one or two length/percentage values, and scale() accepts one or two numbers. Providing the wrong number or type of arguments triggers this error.
Examples
Incorrect: Comma-separated transform functions
Multiple transforms must be space-separated, not comma-separated.
<divstyle="transform:rotate(45deg),scale(1.5);">Transformed</div>
Correct: Space-separated transform functions
<divstyle="transform:rotate(45deg)scale(1.5);">Transformed</div>
Incorrect: Missing unit on rotation value
The rotate() function requires an angle unit such as deg, rad, grad, or turn.
<divstyle="transform:rotate(45);">Rotated</div>
Correct: Angle value with unit
<divstyle="transform:rotate(45deg);">Rotated</div>
Incorrect: Too many arguments in a function
The rotate() function accepts only one argument.
<divstyle="transform:rotate(45deg,20deg);">Rotated</div>
Correct: Single argument for rotate()
If you need to rotate around a specific axis, use rotateX(), rotateY(), or rotateZ() instead.
<divstyle="transform:rotateZ(45deg);">Rotated on Z axis</div>
Incorrect: Misspelled or non-existent function
<divstyle="transform:roate(30deg)scaleX(2);">Transformed</div>
Correct: Properly spelled function names
<divstyle="transform:rotate(30deg)scaleX(2);">Transformed</div>
Incorrect: Using translate without units on non-zero lengths
<divstyle="transform:translate(50,100);">Moved</div>
Correct: Length values with units
A value of 0 does not require a unit, but all other length values do.
<divstyle="transform:translate(50px,100px);">Moved</div>
Valid Transform Functions Reference
Here are the commonly used transform functions and their expected arguments:
translate(tx)ortranslate(tx, ty)— lengths or percentagestranslateX(tx),translateY(ty),translateZ(tz)— a single length/percentagescale(sx)orscale(sx, sy)— unitless numbersscaleX(sx),scaleY(sy),scaleZ(sz)— a single unitless numberrotate(angle)— a single angle value (e.g.,45deg)rotateX(angle),rotateY(angle),rotateZ(angle)— a single angleskew(ax)orskew(ax, ay)— angle valuesskewX(ax),skewY(ay)— a single anglematrix(a, b, c, d, tx, ty)— exactly six unitless numbersmatrix3d(...)— exactly sixteen unitless numbers
When combining multiple transforms, always separate them with spaces and verify each function's name and argument count against the specification.
The controlslist attribute was proposed to give developers a way to hint to the browser which default media controls to show or hide. It accepts values like nodownload, nofullscreen, and noremoteplayback, allowing you to selectively disable specific buttons in the browser's built-in media player UI. For example, controlslist="nodownload" hides the download button on the video player.
However, this attribute was never adopted into the WHATWG HTML Living Standard or any W3C specification. It remains a Chromium-specific feature, meaning it only works in browsers like Chrome and Edge. Firefox, Safari, and other non-Chromium browsers simply ignore it. Because it's not part of any standard, the W3C HTML Validator rightfully reports it as an invalid attribute.
While using controlslist won't break your page — browsers that don't recognize it will silently ignore it — relying on non-standard attributes has downsides:
- Standards compliance: Your HTML won't validate, which can mask other real issues in validation reports.
- Browser compatibility: The behavior only works in Chromium-based browsers, giving an inconsistent experience across browsers.
- Future uncertainty: Non-standard attributes can be removed or changed without notice.
To fix this, you have a few options. The simplest is to remove the attribute entirely if the customization isn't critical. If you need fine-grained control over media player buttons, the most robust approach is to build custom media controls using JavaScript and the HTMLMediaElement API. For the specific case of disabling remote playback, there is a standardized attribute — disableremoteplayback — that you can use instead.
Examples
❌ Invalid: Using the non-standard controlslist attribute
<videosrc="video.mp4"controlscontrolslist="nodownload nofullscreen"></video>
The validator will report: Attribute "controlslist" not allowed on element "video" at this point.
✅ Valid: Removing the attribute
<videosrc="video.mp4"controls></video>
The simplest fix is to remove controlslist and accept the browser's default controls.
✅ Valid: Using custom controls with JavaScript
<videoid="my-video"src="video.mp4"></video>
<divclass="custom-controls">
<buttonid="play-btn">Play</button>
<inputid="seek-bar"type="range"min="0"max="100"value="0">
<buttonid="fullscreen-btn">Fullscreen</button>
</div>
<script>
constvideo=document.getElementById("my-video");
document.getElementById("play-btn").addEventListener("click",()=>{
video.paused?video.play():video.pause();
});
</script>
By omitting the controls attribute and building your own UI, you have full control over which buttons appear — across all browsers.
✅ Valid: Using disableremoteplayback for that specific need
<videosrc="video.mp4"controlsdisableremoteplayback></video>
If your goal was specifically controlslist="noremoteplayback", the standardized disableremoteplayback attribute achieves the same result and is valid HTML.
Audio element
The same issue and solutions apply to the <audio> element:
<!-- ❌ Invalid -->
<audiosrc="song.mp3"controlscontrolslist="nodownload"></audio>
<!-- ✅ Valid -->
<audiosrc="song.mp3"controls></audio>
The margin shorthand property sets the margin area on all four sides of an element. It accepts one to four values, where each value must be a valid CSS length (e.g., 10px, 1em, 0), a percentage, or the keyword auto. When the validator reports "Too many values or values are not recognized," it means either more than four values were supplied, or at least one of the values is something CSS doesn't understand — such as a misspelled unit, a missing unit on a non-zero number, or an invalid keyword.
Common causes of this error include:
- Too many values: Providing five or more values (e.g.,
margin: 1px 2px 3px 4px 5px). The shorthand accepts a maximum of four. - Missing units: Writing a non-zero number without a unit (e.g.,
margin: 10instead ofmargin: 10px). Only0is valid without a unit. - Typos or invalid units: Using a misspelled or nonexistent unit like
margin: 10xpormargin: 10pixels. - Invalid keywords: Using a keyword that isn't recognized in the
margincontext (e.g.,margin: none). The only non-global keywordmarginaccepts isauto. - Missing separators or extra characters: Including commas or other unexpected characters between values (e.g.,
margin: 10px, 20px). Values should be separated by spaces, not commas.
This matters because browsers may ignore or misinterpret an invalid margin declaration entirely, leading to broken or inconsistent layouts across different browsers. Writing valid CSS ensures predictable rendering and easier maintenance.
How margin shorthand values work
The number of values you provide determines how they are applied:
- 1 value: Applied to all four sides.
margin: 10px→ top, right, bottom, and left all get10px. - 2 values: First is top and bottom, second is left and right.
margin: 10px 20px→ top/bottom10px, left/right20px. - 3 values: First is top, second is left and right, third is bottom.
margin: 10px 20px 30px. - 4 values: Applied clockwise — top, right, bottom, left.
margin: 10px 20px 30px 40px.
Examples
❌ Too many values
/* Five values — invalid */
.box{
margin:10px20px30px40px50px;
}
❌ Missing unit on a non-zero number
.box{
margin:1020px;
}
❌ Invalid keyword
.box{
margin: none;
}
❌ Comma-separated values
.box{
margin:10px,20px;
}
✅ Correct: one to four valid values
/* All four sides */
.box{
margin:10px;
}
/* Top/bottom and left/right */
.box{
margin:10px20px;
}
/* Top, left/right, bottom */
.box{
margin:10px auto 20px;
}
/* Top, right, bottom, left */
.box{
margin:10px20px30px40px;
}
✅ Correct: using auto for centering
.container{
margin:0 auto;
}
✅ Correct: zero without a unit
.box{
margin:0;
}
✅ Correct: using global keywords
.box{
margin: inherit;
}
If you need to set margins on more than four sides independently (which isn't possible — elements only have four sides), you likely have a logic error. If you want fine-grained control, use the individual longhand properties (margin-top, margin-right, margin-bottom, margin-left) instead of the shorthand.
The padding-left property accepts a valid CSS length value, a percentage, or the keyword 0. A CSS length is always composed of two parts: a number and a unit (e.g., 10px, 2em, 1.5rem). Writing just px with no number is syntactically invalid — it's a bare unit with no magnitude, so the browser cannot determine what spacing to apply. This commonly occurs due to a typo, a missing variable in a template or preprocessor, or accidentally deleting the numeric portion during editing.
When the validator encounters this in a style attribute, it flags the value as invalid CSS. While most browsers will simply ignore the malformed declaration and fall back to the default padding, relying on this error-recovery behavior leads to unpredictable layouts. Fixing the issue ensures your styles are applied consistently across all browsers and that your markup passes validation.
How to fix it
- Add a numeric value before the unit: change
pxto something like10px,1em, or5%. - If you want zero padding, use
0— no unit is needed (though0pxis also valid). - Check template variables and preprocessors. If you're using a system like PHP, JavaScript templating, or a CSS preprocessor (Sass, Less), make sure the variable that should supply the number isn't empty or undefined. For example,
padding-left: <?= $indent ?>px;will producepadding-left: px;if$indentis empty.
Examples
Incorrect: bare unit with no number
<divstyle="padding-left: px;">Content</div>
The value px has no numeric component, so it is not a valid length.
Correct: numeric value before the unit
<divstyle="padding-left:10px;">Content</div>
Correct: zero padding (no unit required)
<divstyle="padding-left:0;">Content</div>
Incorrect: empty variable producing a bare unit
This is a common source of the bug in templated or dynamically generated HTML:
<!-- If the variable is empty, this renders as "padding-left: px;" -->
<divstyle="padding-left: px;">Content</div>
Correct: ensuring a fallback value
When generating styles dynamically, always provide a sensible default so the output is valid even if the variable is missing:
<divstyle="padding-left:16px;">Content</div>
Using an external stylesheet
The same rule applies in external or embedded CSS. The incorrect version:
.sidebar{
padding-left: px;
}
The corrected version with a proper numeric value:
.sidebar{
padding-left:20px;
}
Other valid padding-left values
Any valid CSS length or percentage works:
<divstyle="padding-left:2em;">Em-based padding</div>
<divstyle="padding-left:1.5rem;">Rem-based padding</div>
<divstyle="padding-left:5%;">Percentage-based padding</div>
The font-style and font-weight properties serve different purposes. font-style controls whether text appears in a normal, italic, or oblique style, while font-weight controls how thick or thin the characters are rendered. Writing font-style: bold is a mistake because bold is not among the accepted values for font-style. Browsers will ignore the invalid declaration entirely, meaning your text won't become bold at all — it will simply render in the default weight.
This error typically comes from confusing the two properties or misremembering which property handles boldness. The valid values for each property are:
font-style:normal,italic,oblique, orobliquewith an angle (e.g.,oblique 10deg)font-weight:normal,bold,bolder,lighter, or numeric values from100to900
To fix this issue, replace font-style: bold with font-weight: bold. If you intended to make text both bold and italic, you'll need to use both properties separately.
Examples
Incorrect — using bold with font-style
This triggers the validation error because bold is not a valid font-style value:
<pstyle="font-style: bold;">This text won't actually be bold.</p>
Correct — using font-weight for boldness
Move the bold value to the font-weight property:
<pstyle="font-weight: bold;">This text is bold.</p>
Correct — combining bold and italic
If you want text that is both bold and italic, use both properties:
<pstyle="font-weight: bold;font-style: italic;">This text is bold and italic.</p>
Correct — using font-weight in a stylesheet
You can also apply bold styling through a <style> block or external stylesheet, using either keyword or numeric values:
<style>
.emphasis{
font-weight: bold;
}
.light{
font-weight:300;
}
.heavy{
font-weight:900;
}
</style>
<pclass="emphasis">This text is bold (weight 700).</p>
<pclass="light">This text is light (weight 300).</p>
<pclass="heavy">This text is extra heavy (weight 900).</p>
Note that the keyword bold is equivalent to the numeric value 700, and normal is equivalent to 400. Numeric values give you finer control over text weight, especially when using variable fonts or font families that offer multiple weight variations.
The spacing() function is not a valid CSS value. It does not exist in any CSS specification.
The spacing() notation is commonly found in utility-based frameworks like Tailwind CSS or custom design systems where it acts as a shorthand for spacing scales. However, browsers and the W3C validator do not recognize it as valid CSS.
If you're using a build tool or preprocessor, make sure spacing() is being compiled into a valid CSS value before it reaches the browser. If you're writing plain CSS, replace it with a standard CSS length value such as px, rem, em, or use a CSS custom property.
How to Fix
Replace spacing(3) with a valid CSS length value:
#content::after{
margin-bottom:0.75rem;
}
Or use a CSS custom property to create your own spacing scale:
:root{
--spacing-3:0.75rem;
}
#content::after{
margin-bottom:var(--spacing-3);
}
Both approaches produce valid CSS that the W3C validator will accept. If your project relies on a framework that provides spacing(), check that your build pipeline (e.g., PostCSS, Sass, or Tailwind) is correctly transforming it into standard CSS before deployment.
The aria-labelledby attribute is part of the WAI-ARIA specification and provides an accessible name for an element by referencing the id values of other elements that contain the labeling text. Without the aria- prefix, labelledby is simply an unrecognized attribute that browsers and assistive technologies will ignore. This means your SVG graphic won't have the accessible label you intended, leaving screen reader users without a meaningful description of the content.
This issue is especially important for <svg> elements because SVG graphics are often used for icons, charts, and illustrations that need descriptive labels for accessibility. Using the incorrect attribute name means the graphic is effectively unlabeled for users who rely on assistive technology.
How to Fix It
Replace labelledby with aria-labelledby on your <svg> element. The attribute's value should be a space-separated list of one or more id values that reference elements containing the label text.
If you want to label an SVG using text that's already visible on the page, aria-labelledby is the ideal approach. You can also reference a <title> element inside the SVG itself.
Examples
❌ Incorrect: Using labelledby (invalid attribute)
<h2id="chart-title">Monthly Sales</h2>
<svglabelledby="chart-title"role="img"viewBox="0 0 200 100">
<!-- chart content -->
</svg>
✅ Correct: Using aria-labelledby to reference an external heading
<h2id="chart-title">Monthly Sales</h2>
<svgaria-labelledby="chart-title"role="img"viewBox="0 0 200 100">
<!-- chart content -->
</svg>
✅ Correct: Using aria-labelledby to reference the SVG's own <title>
<svgaria-labelledby="icon-title"role="img"viewBox="0 0 24 24">
<titleid="icon-title">Search</title>
<pathd="M15.5 14h-.79l-.28-.27A6.47 6.47 0 0 0 16 9.5 6.5 6.5 0 1 0 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5z"/>
</svg>
✅ Correct: Referencing multiple label sources
You can combine multiple id values to build a composite accessible name, separated by spaces:
<h2id="section-title">Revenue</h2>
<pid="section-desc">Q1 2024 revenue by region</p>
<svgaria-labelledby="section-title section-desc"role="img"viewBox="0 0 400 200">
<!-- chart content -->
</svg>
In this case, a screen reader would announce something like "Revenue Q1 2024 revenue by region" as the accessible name for the SVG.
Tips
- When using
aria-labelledbyon<svg>, also addrole="img"to ensure consistent behavior across screen readers. - If the SVG is purely decorative, use
aria-hidden="true"instead of labeling it. - The
aria-labelledbyattribute overrides other labeling mechanisms likearia-labelor the<title>element, so use it when you want a specific label to take precedence.
Character encoding tells the browser how to map the raw bytes of your HTML file into readable characters. When no encoding is declared, browsers must rely on heuristics or defaults to figure out which encoding to use. The validator's fallback to "windows-1252" reflects the behavior described in the HTML specification: if no encoding information is found, parsers may default to this legacy encoding. This can cause serious problems — characters like curly quotes, em dashes, accented letters, emoji, and non-Latin scripts can appear as garbled text (often called "mojibake") if the actual encoding of the file doesn't match what the browser assumes.
Why this matters
- Correctness: If your file is saved as UTF-8 (which is the default in most modern editors) but the browser interprets it as windows-1252, multi-byte characters will render incorrectly.
- Standards compliance: The WHATWG HTML Living Standard requires that a character encoding declaration be present. The encoding must also be declared within the first 1024 bytes of the document.
- Security: Ambiguous encoding can be exploited in certain cross-site scripting (XSS) attacks where an attacker takes advantage of encoding mismatches.
- Interoperability: Different browsers may choose different fallback encodings, leading to inconsistent rendering across platforms.
How to fix it
The simplest and recommended fix is to add <meta charset="utf-8"> as the first child element inside <head>, before <title> or any other elements. It must appear within the first 1024 bytes of the document so the parser encounters it early enough.
UTF-8 is the universal standard for the web. It can represent every character in Unicode, is backward-compatible with ASCII, and is the encoding recommended by the WHATWG HTML specification. Unless you have a very specific reason to use another encoding, always use UTF-8.
You should also ensure your text editor or build tool is actually saving the file in UTF-8 encoding. Declaring <meta charset="utf-8"> while the file is saved in a different encoding will still produce garbled text.
An alternative (less common) approach is to declare the encoding via an HTTP Content-Type header sent by the server, such as Content-Type: text/html; charset=utf-8. However, the <meta> tag is still recommended as a fallback for when files are viewed locally or cached without headers.
Examples
❌ Missing character encoding declaration
This document has no encoding declaration, triggering the validator warning:
<!DOCTYPE html>
<htmllang="en">
<head>
<title>My Page</title>
</head>
<body>
<p>Héllo, wörld! — enjoy "quotes" and emöji 🎉</p>
</body>
</html>
✅ Fixed with <meta charset="utf-8">
Adding the <meta charset="utf-8"> tag as the first element in <head> resolves the issue:
<!DOCTYPE html>
<htmllang="en">
<head>
<metacharset="utf-8">
<title>My Page</title>
</head>
<body>
<p>Héllo, wörld! — enjoy "quotes" and emöji 🎉</p>
</body>
</html>
❌ Encoding declared too late
The <meta charset> must come before other content in the <head>. Placing it after a <title> that contains non-ASCII characters means the parser may have already committed to a wrong encoding:
<!DOCTYPE html>
<htmllang="en">
<head>
<title>Café Menu</title>
<metacharset="utf-8">
</head>
<body>
<p>Welcome to the café.</p>
</body>
</html>
✅ Encoding declared before all other content
<!DOCTYPE html>
<htmllang="en">
<head>
<metacharset="utf-8">
<title>Café Menu</title>
</head>
<body>
<p>Welcome to the café.</p>
</body>
</html>
The key takeaway: always place <meta charset="utf-8"> as the very first element inside <head>. This is a small addition that prevents a whole class of character rendering and security issues.
In CSS, most numeric values of 0 don't need a unit — for example, margin: 0 is perfectly valid because the specification allows unitless zero for <length> values. However, this exception does not apply to <time> values. Properties that accept <time> values, such as transition-delay, transition-duration, animation-delay, and animation-duration, always require a unit (s for seconds or ms for milliseconds), even when the value is zero.
The CSS specification explicitly states that <time> values must include a unit. The unitless 0 shorthand is only permitted for <length> and a few other value types. While some browsers may silently accept transition-delay: 0 and treat it as 0s, this behavior is non-standard and not guaranteed across all browsers or future implementations. Relying on it can lead to inconsistent rendering and will fail W3C CSS validation.
This issue commonly appears when transition-delay is set as part of the transition shorthand, or when developers assume that 0 is universally valid without a unit in CSS.
How to fix it
Add the s (seconds) or ms (milliseconds) unit to any <time> value that is currently a bare 0:
0→0sor0ms- Check both longhand properties (
transition-delay,transition-duration) and thetransitionshorthand.
Examples
Incorrect — unitless zero
<style>
.fade{
transition-delay:0;
transition-duration:0.3s;
transition-property: opacity;
}
</style>
<divclass="fade">Hello</div>
The validator reports: CSS: "transition-delay": "0" is not a "transition-delay" value.
Correct — with time unit
<style>
.fade{
transition-delay:0s;
transition-duration:0.3s;
transition-property: opacity;
}
</style>
<divclass="fade">Hello</div>
Incorrect — unitless zero in the transition shorthand
<style>
.btn{
transition: background-color 0.2s ease 0;
}
</style>
<buttonclass="btn">Click me</button>
The fourth value in the transition shorthand is the delay, and 0 without a unit is invalid.
Correct — shorthand with time unit
<style>
.btn{
transition: background-color 0.2s ease 0s;
}
</style>
<buttonclass="btn">Click me</button>
Multiple transitions
When specifying delays for multiple properties, ensure every <time> value has a unit:
<style>
.card{
transition-property: opacity, transform;
transition-duration:0.3s,0.5s;
transition-delay:0s,0.1s;
}
</style>
<divclass="card">Content</div>
The same rule applies to transition-duration and the animation-delay and animation-duration properties — always include s or ms, even for zero values.
The border-style property controls the visual pattern of a border — whether it appears as a solid line, a series of dots, dashes, or other decorative styles. Its valid values are: none, hidden, dotted, dashed, solid, double, groove, ridge, inset, and outset.
The keyword thick is a valid value for border-width, which controls how wide or heavy the border appears. It's one of three named width keywords: thin, medium, and thick. When thick is mistakenly used as a border-style value, the browser cannot interpret the declaration, and the border may not render at all or may fall back to unexpected defaults.
This is a common mix-up because people often think of a "thick border" as a single concept, but CSS separates the concern into two distinct properties: the style (what it looks like) and the width (how thick it is). Both must be set correctly for the border to display as intended. Without a valid border-style, most browsers default to none, meaning no border is visible regardless of other border properties.
To fix the issue, replace thick in your border-style declaration with a valid style keyword, and move thick to border-width if you want a heavier border. Alternatively, you can use the border shorthand to set width, style, and color in a single declaration.
Examples
Incorrect: using thick as a border style
<divstyle="border-style: thick;">This border will not render correctly.</div>
The value thick is not recognized for border-style, so the declaration is invalid.
Correct: separating style and width
<divstyle="border-style: solid;border-width: thick;">This has a thick solid border.</div>
Here, solid defines the border pattern and thick defines the border width — each value is used with the correct property.
Correct: using a specific pixel width
<divstyle="border-style: dashed;border-width:4px;">This has a 4px dashed border.</div>
You can use any length value (like 4px or 0.25em) for border-width instead of the thick keyword for more precise control.
Correct: using the border shorthand
<divstyle="border: thick solid #333;">This uses the border shorthand.</div>
The border shorthand accepts width, style, and color in any order. This is often the most concise way to define a border and avoids confusion between the individual properties.
The W3C validator reports this error when it encounters padding-top: px; — a unit with no numeric component. In CSS, length values are composed of two parts: a number and a unit identifier (e.g., px, em, rem, %, vh). The unit alone is meaningless without a number to quantify it. This typically happens due to a typo, a preprocessor variable that resolved to an empty value, or accidentally deleting the number during editing.
This matters for several reasons. Browsers will discard the invalid declaration entirely, meaning padding-top will fall back to its default or inherited value — which may not be what you intended. This can cause unpredictable layout differences across browsers. Additionally, invalid CSS can interfere with parsing of subsequent declarations in the same rule block, potentially causing other styles to be ignored as well.
To fix this issue:
- Add a numeric value before the unit: change
pxto something like10px,1.5em, or20%. - Use
0without a unit if you want zero padding:padding-top: 0;is valid and preferred overpadding-top: 0px;. - Check preprocessor variables (Sass, Less, etc.) to make sure they resolve to complete values, not just units.
- Remove the declaration entirely if padding-top doesn't need to be set.
Examples
Incorrect: unit without a number
<divstyle="padding-top: px;">Content</div>
The value px is not a valid padding-top value because it lacks a numeric component.
Correct: number with a unit
<divstyle="padding-top:10px;">Content</div>
Correct: zero padding (no unit needed)
<divstyle="padding-top:0;">Content</div>
Incorrect in an external stylesheet
.header{
padding-top: px;
}
Correct in an external stylesheet
.header{
padding-top:16px;
}
Common preprocessor pitfall
If you use a CSS preprocessor like Sass, watch out for variables that might be empty or undefined:
/* If $spacing somehow resolves to empty, this produces "padding-top: px;" */
.card{
padding-top: $spacing +px;
}
/* Safer approach — define the variable with the full value */
.card{
padding-top: $spacing;/* where $spacing: 16px; */
}
Any valid CSS length value will work for padding-top, including px, em, rem, %, vw, vh, ch, and others — as long as a number precedes the unit. The only length value that doesn't require a unit is 0.
The box-shadow property applies one or more shadow effects to an element's box. The W3C CSS validator checks that each value in the declaration conforms to the specification. When it encounters something it doesn't recognize — such as a unitless number (other than 0), a misspelled keyword, or values arranged in the wrong order — it reports that the value is not valid for box-shadow.
The correct syntax for a single box-shadow value is:
box-shadow: none | [inset? && <offset-x> <offset-y> <blur-radius>? <spread-radius>? <color>?]
inset(optional): If present, the shadow is drawn inside the element's border.<offset-x>and<offset-y>(required): Horizontal and vertical offsets. Must be valid CSS lengths with units (e.g.,px,em,rem). The value0is the only length that doesn't require a unit.<blur-radius>(optional): Must be a non-negative length. Defaults to0.<spread-radius>(optional): Can be positive or negative. Defaults to0. You can only include this if you also include<blur-radius>.<color>(optional): Any valid CSS color. Can appear at the beginning or end of the value list.
Common causes of this validation error include:
- Missing units on length values — Writing
10 10instead of10px 10px. - Invalid or misspelled keywords — Using something like
outerboxorshadowsinstead ofinsetornone. - Too many or too few values — Providing five length values when the maximum is four.
- Vendor prefixes — Using
-webkit-box-shadowor non-standard values that the standard validator rejects. - Invalid color values — Using a malformed color like
rgb(0,0,0,0.5)(missing theainrgbafor CSS3 validation) or a typo in a named color. - Incorrect value order — Placing the color between the length values instead of at the start or end.
Fixing this issue ensures your CSS is standards-compliant, which improves cross-browser consistency and reduces the risk of unexpected rendering behavior.
Examples
Missing units on length values
Unitless numbers (except 0) are not valid CSS lengths. This is one of the most common triggers for this error.
<!-- ❌ Invalid: missing units on offset values -->
<divstyle="box-shadow:10105rgba(0,0,0,0.5);">
Shadow text
</div>
<!-- ✅ Valid: all lengths have proper units -->
<divstyle="box-shadow:10px10px5pxrgba(0,0,0,0.5);">
Shadow text
</div>
Invalid keyword
Only none and inset are valid keywords for box-shadow. Any other keyword triggers the error.
<!-- ❌ Invalid: "outset" is not a recognized keyword -->
<divstyle="box-shadow: outset 4px4px8px#333;">
Shadow text
</div>
<!-- ✅ Valid: using the correct "inset" keyword -->
<divstyle="box-shadow: inset 4px4px8px#333;">
Shadow text
</div>
Color value in the wrong position or malformed
The color value should appear either first or last in the shadow definition. Some validators are strict about placement, and a malformed color will always fail.
<!-- ❌ Invalid: color placed between length values -->
<divstyle="box-shadow:2px red 2px5px;">
Shadow text
</div>
<!-- ✅ Valid: color at the end -->
<divstyle="box-shadow:2px2px5px red;">
Shadow text
</div>
Using zero without units alongside other values
While 0 alone doesn't require a unit, mixing it into the declaration is fine — just make sure other values have proper units.
<!-- ✅ Valid: 0 doesn't need a unit -->
<divstyle="box-shadow:0010px2pxrgba(0,0,0,0.75);">
Shadow text
</div>
Multiple shadows
Multiple shadow values are separated by commas. Each individual shadow must independently follow the correct syntax.
<!-- ✅ Valid: two properly formatted shadows -->
<divstyle="box-shadow:2px2px5px#888, inset 0010px2px blue;">
Multiple shadows
</div>
Vendor-prefixed property
The W3C validator does not recognize vendor-prefixed properties. If you need them for legacy browser support, keep the standard property alongside.
<!-- ❌ Triggers a warning or error in the validator -->
<divstyle="-webkit-box-shadow:3px3px6px#000;">
Shadow text
</div>
<!-- ✅ Valid: use the standard property -->
<divstyle="box-shadow:3px3px6px#000;">
Shadow text
</div>
The font-stretch property selects a normal, condensed, or expanded face from a font family. Its valid keyword values are ultra-condensed, extra-condensed, condensed, semi-condensed, normal, semi-expanded, expanded, extra-expanded, and ultra-expanded. It also accepts percentage values (e.g., 50% to 200%). The value bold doesn't fit into any of these categories because it describes font weight (thickness of strokes), not font width (how narrow or wide the characters are).
This error usually happens due to one of two mistakes:
- Confusing
font-stretchwithfont-weight: You intended to make text bold but accidentally used the wrong property. - Typo or copy-paste error in the
fontshorthand: When writing shorthand font declarations, the various sub-properties can easily get mixed up.
The W3C validator flags this because browsers will ignore invalid CSS values, meaning your intended styling won't be applied. Fixing it ensures your styles work as expected across all browsers and pass validation.
How to Fix It
- If you want bold text, use
font-weight: bold(or numeric values like700). - If you want wider or narrower characters, use
font-stretchwith a valid value likecondensedorexpanded. - If you need both, apply each property separately or use the
fontshorthand correctly.
Examples
Incorrect: Using bold with font-stretch
This triggers the validation error because bold is not a valid font-stretch value:
<pstyle="font-stretch: bold;">This text won't render as expected.</p>
Fixed: Using font-weight for boldness
If the intent was to make the text bold, switch to font-weight:
<pstyle="font-weight: bold;">This text is bold.</p>
Fixed: Using font-stretch correctly for width
If the intent was to adjust the character width, use a valid font-stretch value:
<pstyle="font-stretch: expanded;">This text uses an expanded font face.</p>
Using both properties together
You can combine font-weight and font-stretch when you need both bold text and a different font width:
<style>
.styled-text{
font-weight: bold;
font-stretch: condensed;
font-family: Arial, sans-serif;
}
</style>
<pclass="styled-text">This text is bold and condensed.</p>
Valid font-stretch values reference
Here's a quick overview of all valid keyword values for font-stretch:
<style>
.condensed{font-stretch: condensed;}
.normal-width{font-stretch: normal;}
.expanded{font-stretch: expanded;}
.custom-width{font-stretch:75%;}
</style>
<pclass="condensed">Condensed text</p>
<pclass="normal-width">Normal width text</p>
<pclass="expanded">Expanded text</p>
<pclass="custom-width">75% width text</p>
Note that font-stretch only works if the selected font family includes condensed or expanded faces. If the font doesn't have these variations, the property will have no visible effect even with valid values.
The font-style CSS property controls whether text is displayed in a normal, italic, or oblique face from its font-family. It has a limited set of accepted values, and the W3C validator will flag any value that falls outside this set.
This error commonly occurs for a few reasons:
- Confusing
font-stylewithfont-size: Since both properties start withfont-, it's easy to accidentally typefont-style: 1.2emwhen you meantfont-size: 1.2em. Numeric and length values are not valid forfont-style. - Confusing
font-stylewithfont-weight: Writingfont-style: boldis invalid becauseboldis afont-weightvalue, not afont-stylevalue. - Typos in keyword values: Misspelling a valid keyword, such as
font-style: itallicorfont-style: oblque, will trigger this error. - Using the
obliqueangle syntax incorrectly: Whileobliquecan accept an optional angle (e.g.,oblique 10deg), providing an angle without theobliquekeyword or using an invalid unit will cause a validation error.
Using invalid CSS values can lead to unpredictable rendering across browsers. Most browsers will ignore the entire declaration when they encounter an invalid value, meaning your intended styling won't be applied at all. Keeping your CSS valid ensures consistent behavior and makes debugging easier.
Valid font-style values
The accepted values for font-style are:
normal— displays the normal face of the font family.italic— selects the italic face; falls back toobliqueif unavailable.oblique— selects the oblique face; optionally accepts an angle value (e.g.,oblique 10deg). The angle defaults to14degif omitted.- Global CSS values:
inherit,initial,revert,revert-layer,unset.
Examples
Incorrect: size value applied to font-style
This is the most common mistake — using a length value that belongs on font-size:
<pstyle="font-style:1.2em;">This text has an invalid font-style.</p>
Correct: use font-size for size values
<pstyle="font-size:1.2em;">This text has a valid font size.</p>
Incorrect: using bold with font-style
<pstyle="font-style: bold;">This text has an invalid font-style.</p>
Correct: use font-weight for boldness
<pstyle="font-weight: bold;">This text is bold.</p>
Incorrect: misspelled keyword
<pstyle="font-style: itallic;">This text has a typo in font-style.</p>
Correct: properly spelled keyword
<pstyle="font-style: italic;">This text is italic.</p>
Correct: using oblique with an angle
<pstyle="font-style: oblique 12deg;">This text is oblique at 12 degrees.</p>
Quick reference for commonly confused properties
If you're unsure which property to use, here's a quick guide:
| You want to change… | Use this property | Example value |
|---|---|---|
| Italic or oblique text | font-style | italic, oblique |
| Text size | font-size | 1.2em, 16px |
| Text boldness | font-weight | bold, 700 |
| Text decoration | text-decoration | underline, line-through |
An empty alt attribute on an img element is a deliberate signal that the image is purely decorative and carries no meaningful content. According to the WHATWG HTML specification, this maps the element to the "presentation" role in the accessibility tree, effectively hiding it from screen readers and other assistive technologies.
When you add a role attribute to an img with alt="", you're sending contradictory instructions: the empty alt says "this image is decorative, ignore it," while the role attribute says "this image has a specific semantic purpose." Browsers and assistive technologies cannot reliably resolve this conflict, which can lead to confusing or inconsistent behavior for users who rely on screen readers.
This rule exists to enforce clarity in how images are exposed to the accessibility tree. If an image is truly decorative, it should have alt="" and no role. If an image serves a functional or semantic purpose — such as acting as a button, link, or illustration — it should have both a descriptive alt value and, if needed, an appropriate role.
How to fix it
You have two options depending on the image's purpose:
The image is decorative: Remove the
roleattribute entirely. The emptyaltattribute already communicates that the image should be ignored by assistive technologies.The image is meaningful: Provide a descriptive
altvalue that explains the image's purpose. If a specificroleis genuinely needed, keep it alongside the non-emptyalt.
Examples
❌ Incorrect: empty alt with a role attribute
<imgsrc="icon.png"alt=""role="img">
<imgsrc="banner.jpg"alt=""role="presentation">
Even role="presentation" is redundant and invalid here — the empty alt already implies presentational semantics.
✅ Correct: decorative image with no role
<imgsrc="icon.png"alt="">
If the image is decorative, simply remove the role attribute. The empty alt is sufficient.
✅ Correct: meaningful image with a descriptive alt and a role
<imgsrc="warning-icon.png"alt="Warning"role="img">
If the image conveys information, give it a descriptive alt value. The role="img" is typically unnecessary here since img elements already have an implicit role of img when alt is non-empty, but it is at least valid.
✅ Correct: meaningful image used in a specific context
<button>
<imgsrc="search-icon.png"alt="Search">
</button>
Here the image has a descriptive alt and doesn't need an explicit role because its purpose is conveyed through the alt text and its context within the button.
The font-weight property controls the boldness or thickness of text characters. Unlike many other CSS properties, it does not accept length units such as px, em, or %. Instead, it uses a specific set of keywords or unitless numeric values to indicate the desired weight. Supplying an unrecognized value causes the declaration to be ignored by the browser, meaning your intended styling won't be applied, and the text will fall back to the inherited or default weight.
The accepted values for font-weight are:
- Keywords:
normal(equivalent to400),bold(equivalent to700),bolder(relative, one step heavier than the parent),lighter(relative, one step lighter than the parent). - Numeric values: Any number from
1to1000. Historically only multiples of 100 (100through900) were valid, but the CSS Fonts Level 4 specification expanded this to any value in the1–1000range. Note that many validators and older browsers may still only recognize the100–900multiples.
This matters for standards compliance and predictable rendering. An invalid font-weight value is silently discarded by browsers, which can lead to confusing visual results — especially when you expect a specific weight from a variable font or a multi-weight font family.
To fix this issue, identify the invalid value in your CSS and replace it with one of the accepted values listed above. If you were using a pixel or other unit value, simply remove the unit and choose an appropriate numeric weight. If you used a misspelled keyword (e.g., bolded or heavy), replace it with the correct keyword.
Examples
Incorrect: using a length unit
p{
font-weight:20px;
}
The validator reports this because 20px is not a valid font-weight value. The property does not accept length units.
Incorrect: using an invalid keyword
h2{
font-weight: heavy;
}
The keyword heavy is not recognized by the CSS specification for font-weight.
Correct: using valid numeric values
p{
font-weight:300;
}
h2{
font-weight:700;
}
Correct: using valid keywords
p{
font-weight: lighter;
}
h2{
font-weight: bold;
}
Full HTML example
<!DOCTYPE html>
<htmllang="en">
<head>
<metacharset="UTF-8">
<metaname="viewport"content="width=device-width, initial-scale=1.0">
<title>Font Weight Example</title>
<style>
.light{
font-weight:300;
}
.regular{
font-weight: normal;
}
.semi-bold{
font-weight:600;
}
.bold{
font-weight: bold;
}
</style>
</head>
<body>
<pclass="light">This text uses a light font weight (300).</p>
<pclass="regular">This text uses a normal font weight (400).</p>
<pclass="semi-bold">This text uses a semi-bold font weight (600).</p>
<pclass="bold">This text uses a bold font weight (700).</p>
</body>
</html>
Quick reference of common numeric weights
| Value | Typical name |
|---|---|
100 | Thin |
200 | Extra Light |
300 | Light |
400 | Normal / Regular |
500 | Medium |
600 | Semi Bold |
700 | Bold |
800 | Extra Bold |
900 | Black |
Keep in mind that the actual visual effect of a numeric weight depends on whether the loaded font family provides a matching weight. If a font only includes 400 and 700 weights, the browser will map other values to the nearest available weight.
When you write margin-right: px, the browser cannot determine what margin to apply because px alone is not a recognized CSS value — it's just a unit suffix without a quantity. CSS length values are always a combination of a number and a unit (e.g., 10px, 1.5em, 20%), or a specific keyword like auto, inherit, or 0 (which doesn't require a unit). The lone px is meaningless on its own and will be ignored by browsers, which means your intended spacing won't be applied.
This issue typically arises in a few common scenarios:
- A number was accidentally deleted during editing, leaving behind just the unit.
- A CSS preprocessor variable or template expression failed to output a value, resulting in only the unit being rendered.
- A typo or copy-paste error stripped the numeric portion.
Beyond simply not working, invalid CSS can cause unpredictable rendering differences across browsers. It also makes your code harder to maintain, as other developers may not understand the intended value.
To fix this, determine what numeric value you intended and place it directly before the px unit with no space between the number and unit. If no margin is needed, either remove the property entirely or set it to 0.
Examples
Incorrect: unit without a number
<divstyle="margin-right: px;">Content</div>
The validator reports that px is not a valid margin-right value because no number precedes the unit.
Fixed: complete value with number and unit
<divstyle="margin-right:10px;">Content</div>
Fixed: using zero (no unit required)
<divstyle="margin-right:0;">Content</div>
When the value is 0, no unit is needed since zero is the same in all units.
Fixed: using a keyword value
<divstyle="margin-right: auto;">Content</div>
The auto keyword is a valid value for margin-right and is commonly used for centering or pushing elements.
Watch for preprocessor or template issues
If you're using a CSS preprocessor or a templating language, make sure your variables resolve to complete values:
/* Incorrect — if $spacing is empty, this outputs "margin-right: px;" */
.sidebar{
margin-right: px;
}
/* Correct */
.sidebar{
margin-right:16px;
}
Other valid units
Any valid CSS length unit works, as long as a number precedes it:
<divstyle="margin-right:2em;">Em-based margin</div>
<divstyle="margin-right:5%;">Percentage-based margin</div>
<divstyle="margin-right:1.5rem;">Rem-based margin</div>
An invalid value was assigned to the margin-bottom CSS property, and the W3C validator rejected it because it does not match any accepted syntax for that property.
The margin-bottom property accepts a length (e.g., 10px, 2em), a percentage (e.g., 5%), auto, or the global keywords inherit, initial, revert, and unset. The validator raises this error when the value is misspelled, uses a wrong unit, is missing a unit entirely, or contains an otherwise unrecognized token.
Common causes:
- A bare number without a unit, like
margin-bottom: 10instead ofmargin-bottom: 10px. Zero is the only length value that does not require a unit. - A typo in the unit or keyword, like
margin-bottom: 10 px(with a space) ormargin-bottom: auто(mixed character encodings). - An invalid keyword, like
margin-bottom: none. Themargin-bottomproperty does not acceptnone.
Example with the error
<pstyle="margin-bottom: 10">This paragraph has an invalid margin.</p>
The value 10 is not valid because it lacks a unit.
Fixed example
<pstyle="margin-bottom: 10px">This paragraph has a valid margin.</p>
Adding a recognized unit like px, em, rem, or % fixes the error. If the intended value is zero, margin-bottom: 0 is valid without a unit.
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.
CSS custom properties (variables) used in the flex shorthand are not recognized by the W3C CSS validator, even though they work correctly in all modern browsers. This is a known limitation of the validator, not a bug in your code.
The W3C CSS validator performs static analysis and cannot resolve var() expressions at validation time. It doesn't know that --flex-grow will eventually hold a valid value like 1 or 0, so it flags the declaration as invalid. This affects many CSS properties when custom properties are used, not just flex.
You have a few options. You can safely ignore this specific warning since the code is valid per the CSS specification. Alternatively, you can restructure your CSS to apply the variable to a more specific property like flex-grow instead of the shorthand, which sometimes avoids the validator complaint.
HTML Examples
Before: Using var() in the flex shorthand
<style>
:root{
--flex-grow:1;
}
.item{
flex:var(--flex-grow);
}
</style>
<divstyle="display: flex;">
<divclass="item">Content</div>
</div>
After: Using var() on individual flex properties
<style>
:root{
--flex-grow:1;
}
.item{
flex-grow:var(--flex-grow);
flex-shrink:1;
flex-basis:0%;
}
</style>
<divstyle="display: flex;">
<divclass="item">Content</div>
</div>
Both versions produce the same result in browsers. The second approach uses individual flex-grow, flex-shrink, and flex-basis properties, which may reduce validator noise. That said, this is a false positive from the validator — your original code is perfectly valid CSS.
The align-items property controls how flex or grid items are aligned along the cross axis of their container. While many CSS properties accept auto as a value, align-items is not one of them. The CSS specification defines a specific set of accepted values, and using auto will cause the declaration to be ignored by browsers, potentially breaking your intended layout.
This mistake often stems from confusion with the related property align-self, which does accept auto as its default value. When align-self is set to auto, it defers to the parent container's align-items value. However, align-items itself has no such delegation mechanism — it is the property that sets the default alignment for all items in the container.
The valid values for align-items include:
normal— behaves asstretchin flex containers and has context-dependent behavior in other layout modes.stretch— items are stretched to fill the container along the cross axis (the default behavior in flexbox).center— items are centered along the cross axis.flex-start/start— items are aligned to the start of the cross axis.flex-end/end— items are aligned to the end of the cross axis.baseline/first baseline/last baseline— items are aligned based on their text baselines.self-start/self-end— items are aligned based on their own writing mode.
If you intended the default behavior, use stretch (for flexbox) or normal. If you were trying to reset the property, use initial, unset, or revert instead of auto.
Examples
Incorrect: using auto as a value
<divstyle="display: flex;align-items: auto;">
<p>Item one</p>
<p>Item two</p>
</div>
This triggers the validation error because auto is not a recognized value for align-items.
Fixed: using stretch for default flexbox behavior
<divstyle="display: flex;align-items: stretch;">
<p>Item one</p>
<p>Item two</p>
</div>
Fixed: using center to center items
<divstyle="display: flex;align-items: center;">
<p>Item one</p>
<p>Item two</p>
</div>
Fixed: using flex-start to align items to the top
<divstyle="display: flex;align-items: flex-start;">
<p>Item one</p>
<p>Item two</p>
</div>
Correct use of auto with align-self
If your intention was to let a specific child item defer to its parent's alignment, use align-self: auto on the child element instead:
<divstyle="display: flex;align-items: center;">
<p>Centered item</p>
<pstyle="align-self: auto;">Also centered (defers to parent)</p>
<pstyle="align-self: flex-end;">Aligned to the end</p>
</div>
Here, align-self: auto is valid on individual items and tells them to inherit the align-items value from the container.
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.
NaN in JavaScript stands for "Not a Number" and appears when a numeric operation fails — for example, parsing a non-numeric string with parseFloat(), dividing 0 by 0, or referencing an undefined variable in arithmetic. When this NaN value gets concatenated with a unit string like "rem", the result is "NaNrem", which is meaningless to CSS. The browser cannot interpret it, and the W3C validator flags it as an invalid letter-spacing value.
This issue almost always originates from dynamically generated styles — either through JavaScript that sets inline styles, a server-side template that computes CSS values, or a CSS-in-JS library. The rendered HTML ends up containing something like style="letter-spacing: NaNrem", which the validator rightly rejects.
Beyond validation, this is a practical problem: the browser will ignore the invalid declaration entirely, so whatever letter-spacing you intended won't be applied. Your layout may look different than expected, and the invalid value in the markup signals a bug in your code that could affect other computed styles too.
How to Fix It
Trace the source of the value. Search your codebase for where
letter-spacingis set. If it's an inline style, look at the JavaScript or server-side code that generates it.Validate the number before using it. In JavaScript, use
Number.isNaN()orisFinite()to check that a computed value is valid before applying it.Provide a sensible fallback. If the calculation might fail, default to a known-good value like
0ornormal.Fix the root cause. Determine why the calculation produces
NaN— common causes include missing data attributes,undefinedvariables, or parsing non-numeric strings.
Examples
❌ Invalid: NaN concatenated with a unit
This is what the rendered HTML looks like when the bug occurs:
<pstyle="letter-spacing:NaNrem">Spaced text</p>
The JavaScript that likely produced it:
// Bug: getAttribute returns null if data-spacing is missing
letspacing=parseFloat(element.getAttribute('data-spacing'));
element.style.letterSpacing=spacing+'rem';// "NaNrem" if attribute is missing
✅ Fixed: Validate the value before applying it
letraw=parseFloat(element.getAttribute('data-spacing'));
letspacing=Number.isFinite(raw)?raw:0.1;// fallback to 0.1
element.style.letterSpacing=spacing+'rem';
This produces valid inline CSS:
<pstyle="letter-spacing: 0.1rem">Spaced text</p>
✅ Fixed: Using a static CSS value
If the letter-spacing doesn't need to be dynamic, the simplest fix is to use a plain CSS rule instead of computing it in JavaScript:
<style>
.spaced-text{
letter-spacing:0.1rem;
}
</style>
<pclass="spaced-text">Spaced text</p>
✅ Fixed: Server-side template with a guard
If a server-side template generates the style, add a check before rendering:
<!-- Pseudocode for a template engine -->
<!-- Only output the style attribute if the value is a valid number -->
<pstyle="letter-spacing: 0.05rem">Spaced text</p>
Ensure your template logic verifies the value is numeric before injecting it into the markup. If the value is missing or invalid, either omit the style attribute entirely or use a safe default.
Valid letter-spacing values for reference
The letter-spacing property accepts:
- The keyword
normal(default, lets the browser decide) - Any valid CSS length:
0.1rem,1px,0.05em,2px, etc. 0(no extra spacing)
The numeric part must always be a real number — NaN, Infinity, and empty strings are never valid.
An invalid value was assigned to the padding-bottom CSS property inside a style attribute, and the W3C validator rejected it.
The padding-bottom property accepts a length (e.g., 10px, 2em), a percentage (e.g., 5%), or the keyword inherit. Values like auto, bare numbers without units, or unrecognized keywords are not valid. A common mistake is writing padding-bottom: 10 instead of padding-bottom: 10px, or using a value meant for a different property.
The validator specifically checks inline styles in style attributes against CSS grammar rules. Even if a browser silently ignores the bad value, the markup is still invalid.
Invalid example
<divstyle="padding-bottom: auto;">
Content here
</div>
The value auto is not valid for padding-bottom.
Valid example
<divstyle="padding-bottom:10px;">
Content here
</div>
Use a supported value: a length with a unit (px, em, rem, %, etc.) or 0 (which does not require a unit).
The margin-top property accepts several types of values: lengths (like 10px, 1.5em, 2rem), percentages (like 5%), the keyword auto, or the value 0. When you write margin-top: px, the browser encounters a bare unit with no associated number, which is meaningless — it doesn't know how many pixels you want. Browsers will ignore the invalid declaration entirely, which means margin-top will fall back to its default or inherited value. This can lead to unexpected layout results that may differ across browsers.
This error commonly happens due to a typo, an accidental deletion of the numeric portion, or a templating/build tool that failed to interpolate a variable (e.g., margin-top: ${value}px where value was empty). It can also occur when editing CSS quickly and removing the number while intending to change it.
Beyond just margin-top, this same principle applies to all CSS properties that accept length values — margin, padding, width, height, font-size, border-width, and many others. A bare unit without a number is never valid.
Note: The value 0 is the only numeric length that does not require a unit. Writing margin-top: 0 is perfectly valid and equivalent to margin-top: 0px.
How to fix it
- Add the missing number before the unit. Determine the spacing you need and prepend it to the unit (e.g.,
10px,1.5em). - Use a valid keyword if you don't need a specific numeric value —
autoorinherit, for example. - Check template variables if you use a preprocessor or templating system. Make sure the variable that provides the number is defined and not empty.
Examples
Incorrect: bare unit with no number
<divstyle="margin-top: px;">Content</div>
The validator reports that "px" is not a valid margin-top value because it lacks a numeric component.
Correct: number followed by a unit
<divstyle="margin-top:10px;">Content</div>
Correct: using zero without a unit
<divstyle="margin-top:0;">Content</div>
Correct: using a keyword value
<divstyle="margin-top: auto;">Content</div>
Incorrect in a stylesheet
<style>
.box{
margin-top: px;
}
</style>
<divclass="box">Content</div>
Correct in a stylesheet
<style>
.box{
margin-top:16px;
}
</style>
<divclass="box">Content</div>
Incorrect with CSS preprocessor output
If you use a preprocessor like Sass or a JavaScript framework, an undefined or empty variable can produce this error:
<!-- If the variable was empty, the rendered output becomes: -->
<divstyle="margin-top: px;">Content</div>
Ensure the variable has a valid numeric value so the rendered CSS is complete:
<divstyle="margin-top:20px;">Content</div>
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