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.
When the HTML parser encounters a < character inside an opening tag, it doesn't treat it as the start of a new tag — instead, it tries to interpret it as an attribute name. Since < is not a valid attribute name, the W3C validator raises this error. The browser may still render the page, but the behavior is undefined and can vary across different browsers, potentially leading to broken markup or elements that don't display correctly.
This issue most commonly occurs in a few scenarios:
- Accidental keystrokes — a stray
<typed while editing attributes. - Copy-paste artifacts — fragments of other tags getting pasted into the middle of an element.
- Misplaced angle brackets — attempting to nest or close tags incorrectly, such as adding
<before/>in a self-closing tag. - Template or code generation errors — dynamic HTML output that incorrectly injects
<into attribute positions.
Because this is a syntax-level problem, it can cause cascading parse errors. The parser may misinterpret everything after the stray < until it finds a matching >, which can swallow subsequent elements or attributes and produce unexpected rendering results.
How to Fix It
- Open the file referenced by the validator error and go to the indicated line number.
- Look inside the opening tag of the flagged element for a
<character that doesn't belong. - Remove the stray
<character. - If the
<was meant to represent a literal less-than sign in an attribute value, replace it with the HTML entity<.
Examples
Stray < before the closing slash
<!-- ❌ Stray "<" before the self-closing slash -->
<imgsrc="photo.jpg"alt="smiling cat"</>
<!-- ✅ Fixed: removed the stray "<" -->
<imgsrc="photo.jpg"alt="smiling cat"/>
Stray < between attributes
<!-- ❌ Accidental "<" between attributes -->
<ahref="/about"<class="nav-link">About</a>
<!-- ✅ Fixed: removed the stray "<" -->
<ahref="/about"class="nav-link">About</a>
Fragment of another tag pasted inside an element
<!-- ❌ Leftover "<span" pasted inside the div's opening tag -->
<divclass="card"<span>
<p>Hello world</p>
</div>
<!-- ✅ Fixed: removed the pasted fragment -->
<divclass="card">
<p>Hello world</p>
</div>
Literal < intended in an attribute value
If you actually need a less-than sign inside an attribute value — for example, in a title or data-* attribute — use the < entity instead of a raw <.
<!-- ❌ Raw "<" in an attribute value can cause parsing issues -->
<spantitle="x < 10">Threshold</span>
<!-- ✅ Fixed: use the HTML entity -->
<spantitle="x < 10">Threshold</span>
The stroke-width property controls the thickness of the outline (stroke) drawn around shapes and text, primarily used in SVG but also applicable to HTML elements via CSS. According to both the SVG specification and the CSS standard, stroke-width accepts only non-negative values — that is, zero or any positive number, optionally with a CSS length unit like px, em, or rem. A unitless number is also valid and is interpreted in the current coordinate system's user units.
Negative values are logically meaningless for stroke width because you cannot draw an outline with negative thickness. Browsers will typically ignore or discard the invalid declaration, meaning the stroke may render with an unexpected default width or not at all. Beyond rendering issues, using invalid CSS values causes W3C validation errors, which can indicate broader quality problems in your code and may lead to unpredictable behavior across different browsers.
A common cause of this error is dynamic value generation — for example, a CSS calc() expression or a preprocessor variable that inadvertently produces a negative result. If your stroke width is computed, make sure to clamp the value so it never goes below 0.
How to fix it
- Replace negative values with
0or a positive number. If you intended no visible stroke, use0. If you wanted a visible stroke, use the appropriate positive thickness. - Guard computed values. If the value comes from a
calc()expression or CSS custom property, usemax()to ensure the result is never negative — for example,stroke-width: max(0px, calc(10px - 15px)). - Check inline styles and stylesheets. The error can appear in both inline
styleattributes and external/internal CSS. Search your codebase for anystroke-widthdeclaration with a negative number.
Examples
❌ Invalid: negative stroke-width on an HTML element
<pstyle="stroke-width: -1">Some content</p>
This triggers the validator error because -1 is not an allowed value.
✅ Fixed: non-negative stroke-width
<pstyle="stroke-width: 0">Some content</p>
Using 0 removes the stroke entirely and is valid.
❌ Invalid: negative stroke-width on an SVG element
<svgwidth="100"height="100"xmlns="http://www.w3.org/2000/svg">
<circlecx="50"cy="50"r="40"stroke="black"stroke-width="-3"fill="none"/>
</svg>
✅ Fixed: positive stroke-width on an SVG element
<svgwidth="100"height="100"xmlns="http://www.w3.org/2000/svg">
<circlecx="50"cy="50"r="40"stroke="black"stroke-width="3"fill="none"/>
</svg>
✅ Using max() to clamp a computed value
<divstyle="stroke-width:max(0px,calc(5px-10px))">Some content</div>
Here, calc(5px - 10px) would produce -5px, but max(0px, ...) ensures the final value is 0px, keeping the CSS valid.
Unlike margin properties, which accept negative values to pull elements closer together or overlap them, all padding properties (padding-top, padding-right, padding-bottom, padding-left, and the padding shorthand) are defined in the CSS specification to only accept zero or positive lengths. This is because padding represents the space inside an element between its content and its border — a negative internal space is not a meaningful concept.
When you use a negative padding value, browsers will typically ignore the declaration entirely, meaning your layout may not look the way you intended. The W3C validator catches this to help you identify code that won't behave consistently across browsers and doesn't conform to the CSS specification.
If your goal is to reduce the space between elements, negative margin values are the correct tool. If you're trying to shift content upward within a container, consider using position: relative with a negative top offset, or adjust the layout with other techniques like transform: translateY().
Examples
❌ Invalid: negative padding value
<divstyle="padding-top:-20px;">
This element has invalid negative padding.
</div>
The validator will report: CSS: "padding-top": "-20" negative values are not allowed.
✅ Fixed: using zero or positive padding
<divstyle="padding-top:0;">
This element has no top padding.
</div>
<divstyle="padding-top:10px;">
This element has valid positive top padding.
</div>
✅ Alternative: using negative margin instead
If you need to reduce the space above an element, use a negative margin-top:
<divstyle="margin-top:-20px;">
This element is pulled upward with a negative margin.
</div>
❌ Invalid: negative values in the padding shorthand
The same rule applies to the padding shorthand property. Any negative component value is invalid:
<divstyle="padding:-10px20px15px20px;">
Invalid shorthand padding.
</div>
✅ Fixed: all-positive shorthand values
<divstyle="padding:020px15px20px;">
Valid shorthand padding with zero top padding.
</div>
✅ Alternative: using transform for visual offset
If you need to visually shift an element's content upward without affecting layout flow, transform is a clean option:
<divstyle="transform:translateY(-20px);">
This element appears shifted upward.
</div>
An <input type="hidden"> element is inherently invisible to all users. It is not rendered on the page, it cannot receive focus, and browsers automatically exclude it from the accessibility tree. The aria-hidden attribute is designed to hide visible content from assistive technologies like screen readers, but applying it to an element that is already fully hidden serves no purpose.
The HTML specification explicitly forbids the use of aria-hidden on hidden inputs. This restriction exists because combining the two is semantically meaningless — you cannot "hide from assistive technologies" something that is already invisible to everyone. Validators flag this as an error to encourage clean, standards-compliant markup and to help developers avoid misunderstandings about how ARIA attributes interact with native HTML semantics.
This issue commonly arises when aria-hidden="true" is applied broadly to a group of elements (for example, via a script or template) without checking whether specific children already handle their own visibility. It can also happen when developers add ARIA attributes as a precaution, not realizing that the native behavior of type="hidden" already covers accessibility concerns.
To fix this, remove the aria-hidden attribute from any <input> element whose type is hidden. No replacement is needed — the browser already handles everything correctly.
Examples
Incorrect
Adding aria-hidden to a hidden input triggers a validation error:
<formaction="/submit"method="post">
<inputtype="hidden"aria-hidden="true"name="month"value="10">
<inputtype="hidden"aria-hidden="true"name="csrf_token"value="abc123">
<buttontype="submit">Submit</button>
</form>
Correct
Remove the aria-hidden attribute entirely. The hidden inputs are already inaccessible to all users by default:
<formaction="/submit"method="post">
<inputtype="hidden"name="month"value="10">
<inputtype="hidden"name="csrf_token"value="abc123">
<buttontype="submit">Submit</button>
</form>
When aria-hidden is appropriate
The aria-hidden attribute is intended for elements that are visually present but should be hidden from assistive technologies, such as decorative icons:
<buttontype="button">
<spanaria-hidden="true">★</span>
Favorite
</button>
In this case, the decorative star is visible on screen but irrelevant to screen reader users, so aria-hidden="true" correctly prevents it from being announced. This is the proper use case — hiding visible content from the accessibility tree, not redundantly marking already-hidden elements.
The aria-label attribute is not allowed on a label element that is associated with a form control through the for attribute.
A <label> element already provides an accessible name for the form control it's associated with. Adding aria-label to the <label> itself creates a conflict: the aria-label would attempt to override the label's own accessible name, but the label's visible text is what gets passed to the associated form control. This redundancy is not only unnecessary but explicitly prohibited by the HTML specification.
The <label> element's purpose is to be the accessible label for another element. If you want the form control to have an accessible name, simply put that text inside the <label> element as visible content. If you need to provide a different accessible name directly to the form control, place the aria-label on the input element instead.
Incorrect Example
<labelfor="input_email"id="label_input_email"aria-label="Email">
</label>
<inputtype="email"id="input_email">
Correct Example
The simplest fix is to remove the aria-label from the <label>, since the label's text content already serves as the accessible name for the input:
<labelfor="input_email"id="label_input_email">
</label>
<inputtype="email"id="input_email">
If you need the accessible name to differ from the visible label text, place aria-label on the input instead:
<labelfor="input_email"id="label_input_email">
</label>
<inputtype="email"id="input_email"aria-label="Your email address">
The <meta name="description"> element provides a brief summary of a page's content. According to the WHATWG HTML living standard, there must be no more than one <meta> element per document where the name attribute has the value "description". This is a conformance requirement — not just a best practice — meaning that including duplicates produces invalid HTML.
Why this matters
Standards compliance: The HTML specification explicitly states that certain metadata names, including "description", must be unique within a document. Violating this makes your HTML non-conforming.
Search engine behavior: Search engines like Google use the meta description to generate snippet text in search results. When multiple description meta tags are present, search engines must decide which one to use — or may ignore them entirely and pull text from the page body instead. This can result in a less relevant or less compelling snippet, potentially reducing click-through rates.
Maintainability: Duplicate meta descriptions often arise from template conflicts — for example, a CMS injecting one description while a theme or plugin adds another. Having duplicates makes it unclear which description is actually intended, creating confusion for developers maintaining the code.
Common causes
- A CMS or static site generator automatically inserts a
<meta name="description">tag, while the template or theme also hardcodes one. - Multiple HTML partials or includes each contribute their own description meta tag to the
<head>. - Copy-paste errors when building or editing the
<head>section.
How to fix it
- Search your HTML source for all instances of
<meta name="description". - Decide which description best represents the page's content.
- Remove all duplicate instances, keeping only one.
- If your content comes from templates or includes, trace where each tag is generated and ensure only one source outputs the description.
Examples
❌ Invalid: duplicate description meta tags
<!DOCTYPE html>
<htmllang="en">
<head>
<title>About Us</title>
<metaname="description"content="Learn about our company and mission.">
<metaname="description"content="We are a team of passionate developers.">
</head>
<body>
<h1>About Us</h1>
<p>Welcome to our about page.</p>
</body>
</html>
The validator will report an error because two <meta> elements share name="description".
✅ Valid: single description meta tag
<!DOCTYPE html>
<htmllang="en">
<head>
<title>About Us</title>
<metaname="description"content="Learn about our company, mission, and the team of passionate developers behind it.">
</head>
<body>
<h1>About Us</h1>
<p>Welcome to our about page.</p>
</body>
</html>
Here, the two descriptions have been merged into a single, more comprehensive meta description. Alternatively, you could simply keep whichever original description was more accurate and discard the other.
❌ Invalid: duplicates from mixed sources (common template issue)
<head>
<title>Blog Post</title>
<!-- Injected by CMS -->
<metaname="description"content="Auto-generated summary of the blog post.">
<!-- Hardcoded in theme template -->
<metaname="description"content="A blog about web development tips and tricks.">
<metaname="author"content="Jane Smith">
</head>
✅ Valid: single source of truth
<head>
<title>Blog Post</title>
<!-- Injected by CMS (theme duplicate removed) -->
<metaname="description"content="Auto-generated summary of the blog post.">
<metaname="author"content="Jane Smith">
</head>
When fixing template-driven duplicates, decide which system should own the description — typically the CMS, since it can generate page-specific descriptions — and remove the hardcoded one from the theme.
Make sure your final <meta name="description"> content is meaningful, concise (typically 150–160 characters), and accurately reflects what visitors will find on the page.
The aria-checked attribute is not allowed on a label element when that label is associated with a form control like a checkbox or radio button.
When a label is associated with a labelable element (via the for attribute or by nesting), the label acts as an accessible name provider — it doesn't represent the control's state itself. The aria-checked attribute is meant for elements that act as a checkbox or radio button, such as elements with role="checkbox" or role="switch", not for labels that merely describe one.
Adding aria-checked to a label creates conflicting semantics. Assistive technologies already read the checked state from the associated input element, so duplicating or overriding that state on the label causes confusion.
If you need a custom toggle or checkbox, apply aria-checked to the element that has the interactive role, not to the label.
Example with the issue
<labelfor="notifications"aria-checked="true">Enable notifications</label>
<inputtype="checkbox"id="notifications"checked>
Fixed example using a native checkbox
<labelfor="notifications">Enable notifications</label>
<inputtype="checkbox"id="notifications"checked>
The native <input type="checkbox"> already communicates its checked state to assistive technologies — no aria-checked is needed anywhere.
Fixed example using a custom toggle
If you're building a custom control without a native checkbox, apply aria-checked to the element with the appropriate role:
<spanid="toggle-label">Enable notifications</span>
<spanrole="switch"tabindex="0"aria-checked="true"aria-labelledby="toggle-label"></span>
Here, aria-checked is correctly placed on the element with role="switch", which is the interactive control. The label is a separate <span> referenced via aria-labelledby, keeping roles and states cleanly separated.
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>
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.
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