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 grid-column property is a shorthand for grid-column-start and grid-column-end. It defines where a grid item is placed horizontally within a CSS Grid layout. The validator checks that inline style attributes and <style> blocks contain valid CSS, and it will flag any value that doesn't conform to the property's grammar.
Why This Happens
Several kinds of invalid values can trigger this error:
- Using
0as a line number. CSS Grid lines are 1-indexed. Line0does not exist, so values likegrid-column: 0,grid-column: 0 / 3, orgrid-column: span 0are all invalid. - Typos or unrecognized keywords. Values like
grid-column: centerorgrid-column: fullare not valid unless they match named grid lines you've explicitly defined. - Malformed shorthand syntax. Missing the
/separator, using commas instead, or providing too many values will cause a parse error. - Using
spanincorrectly. Thespankeyword must be followed by a positive integer or a named line, e.g.,span 2. Writingspan -1orspan 0is invalid.
Valid Syntax
The grid-column shorthand accepts:
grid-column: <grid-line>/ <grid-line>;
Each <grid-line> can be:
- A positive or negative integer (but not
0) representing a grid line number - A named grid line (e.g.,
content-start) - The
spankeyword followed by a positive integer or a name (e.g.,span 2) auto
If only one value is provided (no /), the end line defaults to auto.
Why It Matters
Invalid CSS values are ignored by browsers, meaning the grid item will fall back to automatic placement. This can cause unexpected layout shifts. Ensuring valid values improves standards compliance, makes your layout predictable across browsers, and prevents silent failures that are hard to debug.
Examples
❌ Invalid: Using 0 as a line number
<divstyle="display: grid;grid-template-columns:repeat(3,1fr);">
<divstyle="grid-column:0/3;">Item</div>
</div>
Grid lines start at 1, so 0 is not a valid line number.
✅ Fixed: Using a valid line number
<divstyle="display: grid;grid-template-columns:repeat(3,1fr);">
<divstyle="grid-column:1/3;">Item</div>
</div>
❌ Invalid: Unrecognized keyword
<divstyle="display: grid;grid-template-columns:repeat(3,1fr);">
<divstyle="grid-column: full;">Item</div>
</div>
The value full is not a valid grid line value unless it's a named line defined in the grid template.
✅ Fixed: Using span to cover all columns
<divstyle="display: grid;grid-template-columns:repeat(3,1fr);">
<divstyle="grid-column:1/-1;">Item</div>
</div>
Using -1 refers to the last grid line, effectively spanning all columns.
❌ Invalid: span 0
<divstyle="display: grid;grid-template-columns:repeat(4,1fr);">
<divstyle="grid-column: span 0;">Item</div>
</div>
The span keyword requires a positive integer. 0 is not valid.
✅ Fixed: Using a positive span value
<divstyle="display: grid;grid-template-columns:repeat(4,1fr);">
<divstyle="grid-column: span 2;">Item</div>
</div>
❌ Invalid: Malformed syntax with a comma
<divstyle="display: grid;grid-template-columns:repeat(3,1fr);">
<divstyle="grid-column:1,3;">Item</div>
</div>
✅ Fixed: Using the / separator
<divstyle="display: grid;grid-template-columns:repeat(3,1fr);">
<divstyle="grid-column:1/3;">Item</div>
</div>
The start and end lines must be separated by a /, not a comma.
Quick Reference of Valid Patterns
| Value | Meaning |
|---|---|
grid-column: 2 | Start at line 2, end at auto |
grid-column: 2 / 5 | Start at line 2, end at line 5 |
grid-column: 1 / -1 | Span from first to last line |
grid-column: span 3 | Span 3 columns from auto-placed start |
grid-column: 2 / span 3 | Start at line 2, span 3 columns |
grid-column: auto / auto | Fully automatic placement |
When in doubt, check that every numeric value is a non-zero integer and that the overall format uses / to separate the start and end values.
The border shorthand property lets you set the width, style, and color of an element's border in a single declaration. The CSS specification allows up to three values, each corresponding to one of the longhand properties: border-width, border-style, and border-color. Each component may appear at most once, and the browser determines which value maps to which component based on the value's type. When the validator encounters more values than expected or a value it can't match to any of the three components, it raises this error.
This error commonly occurs for several reasons:
- Too many values — Providing four values (like you might with
marginorpadding) doesn't work withborder. Unlike box-model spacing properties,borderdoes not accept per-side values in its shorthand. - Misspelled keywords — A typo like
sollidinstead ofsolid, ordotedinstead ofdotted, produces an unrecognized value. - Invalid or unsupported values — Using values that don't belong to any of the three components, such as
border: 2px solid black inset(mixing shorthand with a style that creates a duplicate). - Missing spaces — Writing
1pxsolid blackinstead of1px solid blackcreates an unrecognized token. - Using
bordersyntax forborder-radiusor other properties — Accidentally placing values like5px 10px 5px 10pxonborderinstead of onborder-radius.
Fixing the issue means ensuring your border value contains only recognized values, with no more than one from each category:
- Width: A length (e.g.,
1px,0.5em),0, or a keyword (thin,medium,thick). - Style: One of
none,hidden,dotted,dashed,solid,double,groove,ridge,inset, oroutset. - Color: Any valid CSS color (e.g.,
red,#333,rgb(0, 0, 0),transparent).
If you need different borders on each side, use the side-specific properties (border-top, border-right, border-bottom, border-left) or the individual longhand properties (border-width, border-style, border-color), which do accept multiple values for each side.
Examples
Incorrect: too many values
<divstyle="border:1px2px solid black;">Content</div>
This provides two width values (1px and 2px), which the border shorthand does not allow. If you want different widths per side, use border-width separately.
Incorrect: misspelled keyword
<divstyle="border:2px sollid red;">Content</div>
The value sollid is not a recognized border style, causing the validator to reject the declaration.
Incorrect: four-value syntax used on border
<divstyle="border:1px2px1px2px solid grey;">Content</div>
The border shorthand does not support per-side values. This syntax is valid for border-width, not for border.
Correct: standard shorthand with all three components
<divstyle="border:2px solid black;">Content</div>
Correct: omitting optional components
You don't need to provide all three values. Any omitted component resets to its initial value (medium, none, and currentcolor respectively).
<pstyle="border: solid;">Content</p>
Correct: two components in any order
<pstyle="border: dashed #00f;">Content</p>
Correct: different borders per side using longhand properties
<divstyle="border-width:1px2px1px2px;border-style: solid;border-color: grey;">Content</div>
Correct: using side-specific shorthand properties
<divstyle="border-top:1px solid red;border-bottom:2px dashed blue;">Content</div>
The padding-block shorthand property sets padding on the block-start and block-end sides of an element. In horizontal writing modes (like English), this corresponds to the top and bottom padding; in vertical writing modes, it maps to left and right. It's the logical equivalent of combining padding-block-start and padding-block-end.
The reason auto is invalid here is that padding, by definition in the CSS specification, must resolve to a definite size. Margins can be auto because the browser uses that value in layout algorithms to distribute remaining space (e.g., centering a block element with margin-inline: auto). Padding, however, adds space inside an element's border and has no such auto-distribution behavior defined in the spec. Attempting to use auto will cause the declaration to be ignored by browsers, meaning no padding is applied, which can lead to unexpected layout results.
This validation error often arises when developers confuse padding-block with margin-block, or when they copy centering patterns that work with margins and try to apply them to padding. If your intent was to center content, consider using margin-block: auto instead, or use Flexbox/Grid alignment properties.
How to Fix
Replace auto with a valid value:
- Length values:
0,10px,1em,1.5rem, etc. - Percentage values:
5%,2% 1%, etc. (relative to the inline size of the containing block). - Two values:
padding-block: 20px 10px;setspadding-block-startto20pxandpadding-block-endto10px. - CSS-wide keywords:
inherit,initial,revert,revert-layer, orunset.
If you used auto to try to eliminate padding, use 0 instead. If you used it to try to center something, switch to margins or a layout method like Flexbox.
Examples
Incorrect: using auto as a padding-block value
<style>
.box{
padding-block: auto;
}
</style>
<divclass="box">This box has invalid padding.</div>
The browser will ignore the padding-block: auto declaration entirely, and the W3C validator will flag it as an error.
Correct: using length values
<style>
.box{
padding-block:20px10px;
}
</style>
<divclass="box">20px padding on block-start, 10px on block-end.</div>
Correct: using a single value for equal padding
<style>
.box{
padding-block:1em;
}
</style>
<divclass="box">1em padding on both block-start and block-end.</div>
Correct: removing padding with zero
<style>
.box{
padding-block:0;
}
</style>
<divclass="box">No block padding.</div>
If you intended to center: use margin-block instead
<style>
.container{
display: flex;
flex-direction: column;
height:300px;
}
.centered{
margin-block: auto;
}
</style>
<divclass="container">
<divclass="centered">This element is vertically centered using margin-block: auto.</div>
</div>
The margin-block: auto approach works inside flex or grid containers to distribute space evenly, achieving vertical centering. This is likely what you want if you originally reached for padding-block: auto.
The padding-right property defines the amount of space between an element's content and its right border. Like all CSS length properties, it expects either a valid length value (a number paired with a unit like px, em, rem, %, vw, etc.), the keyword 0 (which needs no unit), or the keyword inherit/initial/unset. A bare unit such as px with no number is meaningless — it doesn't tell the browser how much padding to apply.
This error typically occurs due to a typo, a templating issue where a variable failed to render, or accidental deletion of the numeric portion of the value. For example, a template like padding-right: {{ value }}px; might produce padding-right: px; if value is empty or undefined.
When the browser encounters an invalid value like px, it discards the entire declaration and falls back to the default or inherited value for padding-right. This can lead to unexpected layout differences across browsers and makes your intentions unclear to other developers. Fixing these validation errors also helps maintain clean, predictable stylesheets.
How to Fix
- Add the missing number before the unit: change
pxto a specific value like10px. - Use
0without a unit if you want no padding:padding-right: 0;is valid and preferred overpadding-right: 0px;. - Check template variables and dynamic style generation to ensure numeric values are always output correctly.
Examples
Incorrect: bare unit with no number
<divstyle="padding-right: px;">Content</div>
The value px is not valid because it lacks a numeric component.
Correct: numeric value with unit
<divstyle="padding-right:10px;">Content</div>
Correct: zero padding (no unit needed)
<divstyle="padding-right:0;">Content</div>
Correct: using other valid units
<divstyle="padding-right:2em;">Content</div>
<divstyle="padding-right:5%;">Content</div>
Incorrect in an external stylesheet
.sidebar{
padding-right: px;
}
Fixed in an external stylesheet
.sidebar{
padding-right:16px;
}
Guarding against empty values in templates
If you generate CSS dynamically, make sure the numeric value is always present. For instance, provide a fallback:
.sidebar{
padding-right:16px;/* safe default */
}
Rather than relying on a template that might produce an empty value, consider setting defaults in your CSS and only overriding with inline styles when you're certain the value is valid.
This error is misleading at first glance because the <meta> tag in question is often perfectly well-formed. The real problem is usually above the <meta> tag — an element that doesn't belong in <head> (such as <img>, <div>, <p>, or other flow content) has been placed there. When the HTML parser encounters such an element inside <head>, it implicitly closes the <head> and opens the <body>. From that point on, any subsequent <meta> tags are now technically inside the <body>, where the name attribute on <meta> is not permitted.
In other cases, the error can also occur when a <meta name="..."> tag is explicitly placed inside <body>, or when a typo or malformed tag earlier in the document breaks the expected document structure.
This matters for several reasons. Search engines and social media platforms rely on <meta> tags being in the <head> to extract page descriptions, Open Graph data, and other metadata. If the document structure is broken and <meta> tags end up in the <body>, this metadata may be ignored entirely. Additionally, elements like <img> inside <head> won't render as expected, and the overall document structure will be invalid, potentially causing unpredictable behavior across browsers.
How to fix it
- Look above the flagged
<meta>tag. Find any element in the<head>that doesn't belong there — common culprits include<img>,<div>,<span>,<p>,<a>, or<section>. - Move the offending element into the
<body>where it belongs. - If the
<meta>tag itself is in the<body>, move it into the<head>. - Check for malformed tags above the
<meta>— an unclosed tag or a typo can break the parser's understanding of the document structure.
Only certain elements are allowed inside <head>: <title>, <meta>, <link>, <style>, <script>, <noscript>, <base>, and <template>.
Examples
An invalid element in <head> breaks the context
The <img> tag is not allowed inside <head>. The parser implicitly closes <head> when it encounters it, so the <meta> tag that follows ends up in <body>:
<!DOCTYPE html>
<htmllang="en">
<head>
<title>My Page</title>
<imgsrc="photo.jpg"alt="A smiling cat">
<metaname="description"content="A page about cats">
</head>
<body>
<p>Welcome!</p>
</body>
</html>
Move the <img> into the <body> to fix the issue:
<!DOCTYPE html>
<htmllang="en">
<head>
<title>My Page</title>
<metaname="description"content="A page about cats">
</head>
<body>
<imgsrc="photo.jpg"alt="A smiling cat">
<p>Welcome!</p>
</body>
</html>
A <meta> tag accidentally placed in <body>
<!DOCTYPE html>
<htmllang="en">
<head>
<title>My Page</title>
</head>
<body>
<metaname="author"content="Jane Doe">
<p>Hello world</p>
</body>
</html>
Move the <meta> tag into <head>:
<!DOCTYPE html>
<htmllang="en">
<head>
<title>My Page</title>
<metaname="author"content="Jane Doe">
</head>
<body>
<p>Hello world</p>
</body>
</html>
A malformed tag disrupts the <head>
A missing closing > on a <link> tag can confuse the parser, causing subsequent elements to be misinterpreted:
<!DOCTYPE html>
<htmllang="en">
<head>
<title>My Page</title>
<linkrel="stylesheet"href="style.css"
<metaname="viewport"content="width=device-width, initial-scale=1">
</head>
<body>
<p>Content</p>
</body>
</html>
Close the <link> tag properly:
<!DOCTYPE html>
<htmllang="en">
<head>
<title>My Page</title>
<linkrel="stylesheet"href="style.css">
<metaname="viewport"content="width=device-width, initial-scale=1">
</head>
<body>
<p>Content</p>
</body>
</html>
Nested comments are not allowed in HTML. When you place an opening comment tag <!-- within an existing comment, it causes a parsing error.
To fix this issue, you should avoid nesting comments. If you need to include multiple comments in your HTML code, you can separate them or consider alternative ways to convey the information without nested comments.
Here's an example of a nested comments, which is not allowed in HTML:
<!-- This is a valid comment -->
<!-- This <!-- is not allowed --> nested comment -->
To fix the nested comment issue, you can rewrite the comments like this:
<!-- This is a valid comment -->
<!-- Avoid nesting comments and provide comments separately -->
<!-- Another comment here -->
The background-image CSS property accepts a specific set of value types defined by the CSS specification. The most common are none (the default, meaning no image), the url() function pointing to an image file, and gradient functions like linear-gradient() or radial-gradient(). When the validator encounters a value that doesn't match any of these patterns, it flags the error.
This issue often appears in inline style attributes within HTML, which is where the W3C HTML Validator checks your CSS. Common mistakes include providing a bare filename without url(), forgetting parentheses or quotes, using incorrect gradient syntax, or introducing typos in CSS function names.
Fixing this matters for several reasons. Browsers may silently ignore an invalid background-image declaration entirely, meaning your intended background simply won't appear. This leads to broken visual designs that can be difficult to debug. Additionally, invalid CSS can cause parsing errors that may affect subsequent declarations in the same rule block.
How to fix it
- Wrap image paths in
url()— A bare filename likebackground-image: photo.jpgis invalid. It must bebackground-image: url("photo.jpg"). - Use proper quoting — While quotes inside
url()are technically optional for simple paths, always use them for paths containing spaces, parentheses, or special characters. Single or double quotes both work. - Check gradient syntax — If using gradients, ensure the function name is correct (e.g.,
linear-gradient, notlinear-gradiant) and the arguments follow valid syntax. - Use recognized keywords — The only non-function keyword accepted is
none. Values liketransparent,auto, or arbitrary strings are not valid for this property.
Examples
Incorrect: bare filename without url()
<divstyle="background-image: hero.jpg;">
Content here
</div>
Incorrect: misspelled function name
<divstyle="background-image:urls('hero.jpg');">
Content here
</div>
Incorrect: missing parentheses in url
<divstyle="background-image: url 'hero.jpg';">
Content here
</div>
Incorrect: invalid keyword
<divstyle="background-image: transparent;">
Content here
</div>
Correct: using url() with a file path
<divstyle="background-image:url('hero.jpg');">
Content here
</div>
Correct: using none to explicitly set no background image
<divstyle="background-image: none;">
Content here
</div>
Correct: using a gradient function
<divstyle="background-image:linear-gradient(to right,#ff7e5f,#feb47b);">
Content here
</div>
Correct: multiple background images
<divstyle="background-image:url('overlay.png'),linear-gradient(to bottom,#000,#333);">
Content here
</div>
Correct: using a <style> block
<!DOCTYPE html>
<htmllang="en">
<head>
<title>Background Image Example</title>
<style>
.banner{
background-image:url("banner.png");
background-size: cover;
background-repeat: no-repeat;
}
</style>
</head>
<body>
<divclass="banner">Welcome</div>
</body>
</html>
Always wrap image paths in the url() function, double-check function names for typos, and use quotes around paths that contain special characters. When in doubt, move your styles out of inline style attributes and into a <style> block or external stylesheet, which makes debugging CSS issues much easier.
The border-radius property controls the rounding of an element's corners. Its valid values include lengths (e.g., 5px, 1em), percentages (e.g., 50%), and CSS-wide keywords like inherit, initial, and unset. Unlike many other border-related properties, border-radius has no none keyword in its value syntax.
This confusion typically arises because developers associate "no effect" with the keyword none, which works for properties like border: none or text-decoration: none. However, border-radius describes a geometric measurement — the radius of the corner curve — so "zero radius" (0) is the correct way to express no rounding.
Using an invalid value means the browser will ignore the entire declaration. This can lead to unexpected results: if a parent stylesheet or an earlier rule sets a border-radius, your none declaration won't override it, and the element will retain its rounded corners. Fixing this ensures your CSS is standards-compliant, behaves predictably across browsers, and passes W3C validation.
How to fix it
- To remove rounding, replace
nonewith0. - To set a specific radius, use a valid length (
5px,0.5em), a percentage (50%), or a CSS-wide keyword (inherit,initial,unset). - The same rule applies to the longhand properties:
border-top-left-radius,border-top-right-radius,border-bottom-right-radius, andborder-bottom-left-radius.
Examples
Incorrect: using none
<style>
.box{
border-radius: none;/* "none" is not a valid border-radius value */
}
</style>
<divclass="box">Content</div>
Correct: removing rounded corners with 0
<style>
.box{
border-radius:0;
}
</style>
<divclass="box">Content</div>
Correct: applying a specific radius
<style>
.circle{
width:100px;
height:100px;
border-radius:50%;
}
.rounded{
border-radius:8px;
}
.pill{
border-radius:9999px;
}
</style>
<divclass="circle">Circle</div>
<divclass="rounded">Rounded</div>
<divclass="pill">Pill shape</div>
Correct: resetting to the initial value
If you need to undo a border-radius set by another rule, you can use initial or unset, both of which resolve to 0:
<style>
.card{
border-radius:12px;
}
.card.sharp{
border-radius: initial;/* Resets to 0 */
}
</style>
<divclass="card">Rounded card</div>
<divclass="card sharp">Sharp-cornered card</div>
The mask CSS shorthand property allows you to hide parts of an element by masking or clipping it at specific points. It combines several longhand properties into one declaration: mask-image, mask-mode, mask-repeat, mask-position, mask-clip, mask-origin, mask-size, and mask-composite.
Because mask is a shorthand that accepts values for many sub-properties, it's easy to trigger validation errors. Common causes include:
- Too many values: Providing more values than the shorthand grammar allows, or duplicating values for the same sub-property.
- Unrecognized values: Using vendor-specific values (like
-webkit-prefixed keywords), typos, or values that belong to a different CSS property. - Incorrect value order: The shorthand has a specific grammar. For example,
mask-sizevalues must followmask-positionvalues and be separated by a/, similar to thebackgroundshorthand. - Mixing shorthand and longhand concepts: Trying to set values that aren't part of the
maskshorthand grammar.
The formal syntax for a single mask layer is:
<mask-layer> = <mask-reference> || <position> [ / <bg-size> ]? || <repeat-style> ||
<geometry-box> || [ <geometry-box> | no-clip ] || <compositing-operator> ||
<masking-mode>
This is a problem for standards compliance because invalid CSS can lead to the entire declaration being ignored by browsers, causing your masking effect to silently fail. It also affects cross-browser compatibility — different browsers have varying levels of support for the mask shorthand, and using individual longhand properties is often more reliable.
To fix this issue:
- Check each value in your
maskdeclaration and ensure it's a valid value for one of the mask sub-properties. - Use longhand properties instead of the shorthand if you only need to set one or two aspects of the mask. This avoids ambiguity and improves readability.
- Separate position and size with
/if you're specifying both, e.g.,center / contain. - Remove or separate vendor prefixes — use
-webkit-maskfor WebKit-specific syntax and the standardmaskfor standards-compliant syntax, but don't mix prefixed values into the unprefixed property.
Examples
Incorrect: too many or unrecognized values in the shorthand
<style>
.masked{
/* Error: too many values / unrecognized combination */
mask:url(mask.svg) center center no-repeat contain;
}
</style>
<divclass="masked">Content</div>
Here, contain is a mask-size value but it must be separated from the position with a /. Without the slash, the validator sees an extra unrecognized value.
Correct: proper shorthand syntax with position and size
<style>
.masked{
mask:url(mask.svg) center / contain no-repeat;
}
</style>
<divclass="masked">Content</div>
The / separates mask-position (center) from mask-size (contain), just like in the background shorthand.
Correct: using longhand properties for clarity and compatibility
<style>
.masked{
width:100px;
height:100px;
background-color:#8cffb0;
-webkit-mask-image:url(sun.svg);
mask-image:url(sun.svg);
mask-repeat: no-repeat;
mask-position: center;
mask-size: contain;
}
</style>
<divclass="masked">Content</div>
Using individual longhand properties avoids shorthand parsing issues entirely. Including the -webkit-mask-image prefix alongside the standard mask-image ensures broader browser support.
Incorrect: unrecognized value in the shorthand
<style>
.masked{
/* "luminance" is a mask-mode value but may not be recognized in the shorthand by all validators */
mask:url(mask.png) luminance;
}
</style>
<divclass="masked">Content</div>
Correct: using the longhand for mask mode
<style>
.masked{
mask-image:url(mask.png);
mask-mode: luminance;
}
</style>
<divclass="masked">Content</div>
When in doubt, splitting the mask shorthand into its individual longhand properties is the safest approach. It makes your intent explicit, avoids validation errors, and tends to have better cross-browser support.
The W3C validator checks inline styles and embedded stylesheets for valid CSS. When it encounters a height declaration with multiple values or an unrecognized value, it flags the error because height is not a shorthand property — it only accepts one value at a time. This differs from properties like margin or padding, which accept multiple values to target different sides of an element.
This error commonly occurs when you:
- Accidentally provide two values, perhaps confusing
heightwith a shorthand property (e.g.,height: 100px 50px;). - Include a typo or invalid unit (e.g.,
height: 100ppx;orheight: 100pixels;). - Use a CSS function incorrectly (e.g.,
height: calc(100% 20px);— missing the operator). - Copy a value meant for another property, such as pasting a
grid-template-rowsvalue intoheight.
Browsers may silently ignore invalid height declarations, causing your element to fall back to its default sizing (auto). This can lead to unexpected layout behavior that's difficult to debug. Keeping your CSS valid ensures consistent rendering across browsers and helps catch mistakes early.
Valid values for height
The height property accepts exactly one of the following:
- Length values:
100px,10em,5rem,20vh, etc. - Percentage values:
50%,100% - Keyword values:
auto,max-content,min-content,fit-content(200px) - Global values:
inherit,initial,revert,unset - Calc expressions:
calc(100% - 20px),calc(50vh + 2rem)
Examples
Incorrect: too many values
<style>
.box{
height:100px50px;/* Error: height only accepts one value */
}
</style>
<divclass="box">Content</div>
Incorrect: unrecognized value
<style>
.box{
height:100pixels;/* Error: "pixels" is not a valid unit */
}
</style>
<divclass="box">Content</div>
Incorrect: malformed calc() expression
<style>
.box{
height:calc(100%20px);/* Error: missing operator between values */
}
</style>
<divclass="box">Content</div>
Correct: single length value
<style>
.box{
height:100px;
}
</style>
<divclass="box">Content</div>
Correct: percentage value
<style>
.box{
height:50%;
}
</style>
<divclass="box">Content</div>
Correct: calc() with proper operator
<style>
.box{
height:calc(100%-20px);
}
</style>
<divclass="box">Content</div>
Correct: keyword value
<style>
.box{
height: auto;
}
</style>
<divclass="box">Content</div>
If you need to set both width and height, remember they are separate properties and must be declared individually. If you were trying to set a minimum and maximum height, use min-height and max-height as distinct declarations instead of combining values into a single height property.
The <meta charset="utf-8"> declaration is not only valid but recommended by the HTML living standard. So when the validator complains that the charset attribute is "not allowed at this point," the problem isn't the <meta> tag itself — it's what surrounds it. The HTML parser follows strict rules about which elements can appear inside <head>. When it encounters an element that doesn't belong there (like <img>, <div>, <p>, or other flow/phrasing content), it implicitly closes the <head> and opens the <body>. Any <meta> tags that come after that point are now parsed as being inside <body>, where <meta charset> is not permitted.
This is a problem for several reasons. First, the <meta charset> declaration must appear within the first 1024 bytes of the document so browsers can determine the character encoding early. If the parser moves it out of <head>, browsers may not apply the encoding correctly, potentially leading to garbled text — especially for non-ASCII characters. Second, this often signals a structural error in your HTML that could cause other unexpected rendering issues.
Common causes include:
- An element that only belongs in
<body>(like<img>,<div>,<span>, or<p>) placed before<meta charset>in the<head>. - A stray closing tag (like
</head>) appearing too early. - A
<script>tag with content that causes the parser to break out of<head>.
To fix the issue, inspect the elements that appear before <meta charset> in your <head>. Move any elements that don't belong in <head> into <body>, and place <meta charset="utf-8"> as the very first element inside <head>.
Examples
Incorrect — element before <meta> forces parser out of <head>
An <img> tag inside <head> causes the parser to implicitly close <head> and open <body>. The <meta charset> that follows is now parsed as being in <body>, triggering the error.
<!DOCTYPE html>
<htmllang="en">
<head>
<title>My Page</title>
<imgsrc="photo.jpg"alt="A smiling cat">
<metacharset="utf-8">
</head>
<body>
<p>Some content</p>
</body>
</html>
Correct — <meta charset> first, invalid elements moved to <body>
<!DOCTYPE html>
<htmllang="en">
<head>
<metacharset="utf-8">
<title>My Page</title>
</head>
<body>
<imgsrc="photo.jpg"alt="A smiling cat">
<p>Some content</p>
</body>
</html>
Incorrect — stray <div> in <head> breaks context
<!DOCTYPE html>
<htmllang="en">
<head>
<div>Oops</div>
<metacharset="utf-8">
<title>My Page</title>
</head>
<body>
<p>Hello</p>
</body>
</html>
Correct — only valid head elements before <meta charset>
<!DOCTYPE html>
<htmllang="en">
<head>
<metacharset="utf-8">
<title>My Page</title>
</head>
<body>
<div>Content goes here</div>
<p>Hello</p>
</body>
</html>
Best practice
As a general rule, always make <meta charset="utf-8"> the very first child of <head>. This ensures the browser detects the encoding as early as possible and avoids the risk of other elements accidentally breaking the parser context before the charset is declared.
The pointer-events CSS property controls whether an element can be the target of pointer events such as clicks, taps, and hover states. Unlike many other CSS properties that accept normal as a keyword (e.g., white-space, letter-spacing), the pointer-events property does not include normal in its list of valid values. This is a common mistake since normal and auto are often used interchangeably across different CSS properties, but each property defines its own set of accepted keywords.
Using an invalid value like normal means the browser will ignore the entire declaration. In most cases this won't cause visible breakage because the default behavior already allows pointer interaction, but it can lead to unexpected results if you're relying on the property to override an inherited pointer-events: none from a parent element. The invalid declaration would simply be discarded, and the inherited none value would remain in effect, making the element unclickable.
For standard HTML elements, the two primary values you'll use are:
auto— The element behaves as it normally would regarding pointer events. This is the default.none— The element is never the target of pointer events. Clicks and hovers pass through to whatever is behind it.
Several additional values exist (visiblePainted, visibleFill, visibleStroke, visible, painted, fill, stroke, all) but these only apply to SVG elements. Global CSS keywords like inherit, initial, unset, and revert are also valid.
To fix the issue, replace normal with auto wherever it appears as a pointer-events value. If you're using pointer-events: normal to restore default interactivity after a parent set pointer-events: none, then auto is exactly what you need.
Examples
Incorrect — using normal
<divstyle="pointer-events: normal;">
<ahref="/about">About us</a>
</div>
The validator will flag normal as an invalid value for pointer-events.
Correct — using auto
<divstyle="pointer-events: auto;">
<ahref="/about">About us</a>
</div>
Practical use case: restoring pointer events on a child
A common pattern is disabling pointer events on a parent and re-enabling them on a specific child. Using normal here would silently fail, leaving the button unclickable:
<!-- Incorrect -->
<style>
.overlay{
pointer-events: none;
}
.overlay.close-btn{
pointer-events: normal;/* Invalid — button remains unclickable */
}
</style>
<divclass="overlay">
<buttonclass="close-btn">Close</button>
</div>
<!-- Correct -->
<style>
.overlay{
pointer-events: none;
}
.overlay.close-btn{
pointer-events: auto;/* Valid — button is clickable again */
}
</style>
<divclass="overlay">
<buttonclass="close-btn">Close</button>
</div>
In the incorrect version, the browser discards the invalid pointer-events: normal declaration entirely, so the .close-btn inherits none from the parent and cannot be clicked. Changing it to auto correctly restores interactivity on the button.
The CSS width property sets an element's width and accepts a single value. The W3C validator reports this error when it encounters something it cannot parse as a valid width declaration. Common causes include:
- Missing units: Writing
width: 300instead ofwidth: 300px. CSS requires explicit units for non-zero lengths. - Multiple values: Writing
width: 100px 200pxas ifwidthaccepted shorthand-style multiple values (it doesn't). - Typos or invalid keywords: Writing
width: auotinstead ofwidth: auto, or using a made-up keyword. - Invalid functions or syntax: Using incorrect function syntax like
width: calc(100% - 20px)with missing spaces around operators, or using browser-prefixed values without a standard fallback. - Unsupported values: Using newer CSS values like
fit-contentormax-contentin a context where the validator's CSS level doesn't recognize them.
This matters because invalid CSS can cause browsers to silently discard the entire declaration, meaning your intended layout won't be applied. Different browsers may handle invalid values differently, leading to inconsistent rendering. Keeping your CSS valid ensures predictable, cross-browser behavior.
Valid values for width
The width property accepts exactly one of the following:
- Length values: A number with a unit, such as
300px,25em,10rem,5vw. - Percentage values: A percentage relative to the containing block, such as
75%. - Keyword values:
auto,max-content,min-content,fit-content. - Function values:
fit-content(20em),calc(100% - 40px),min(300px, 100%),max(200px, 50%),clamp(200px, 50%, 600px). - Global values:
inherit,initial,revert,revert-layer,unset.
Note that 0 is the only numeric value that does not require a unit.
Examples
Incorrect: missing unit
<style>
.box{
width:300;
}
</style>
<divclass="box">Content</div>
A bare number (other than 0) is not valid. The browser won't know if you mean pixels, ems, or something else.
Correct: unit provided
<style>
.box{
width:300px;
}
</style>
<divclass="box">Content</div>
Incorrect: too many values
<style>
.sidebar{
width:200px400px;
}
</style>
<asideclass="sidebar">Sidebar</aside>
Unlike properties such as margin or padding, width only accepts a single value.
Correct: single value
<style>
.sidebar{
width:200px;
}
</style>
<asideclass="sidebar">Sidebar</aside>
Incorrect: typo in keyword
<style>
.container{
width: auot;
}
</style>
<divclass="container">Content</div>
Correct: proper keyword
<style>
.container{
width: auto;
}
</style>
<divclass="container">Content</div>
Incorrect: malformed calc() expression
<style>
.panel{
width:calc(100%-40px);
}
</style>
<divclass="panel">Content</div>
The calc() function requires spaces around + and - operators.
Correct: properly spaced calc() expression
<style>
.panel{
width:calc(100%-40px);
}
</style>
<divclass="panel">Content</div>
Incorrect: accidental semicolon or extra text
<style>
.card{
width:50% important;
}
</style>
<divclass="card">Content</div>
If you intended to use !important, the ! is required.
Correct: proper !important syntax
<style>
.card{
width:50%!important;
}
</style>
<divclass="card">Content</div>
The clip-path property defines a clipping region that controls which parts of an element are visible. It accepts a specific set of value types, and any deviation from the expected syntax will trigger a validation error. The validator checks your CSS against the specification and flags values that don't conform.
The accepted value types for clip-path are:
none— No clipping (the default).- Basic shape functions —
inset(),circle(),ellipse(),polygon(), andpath(). url()reference — Points to an SVG<clipPath>element, e.g.,url(#myClip).- Geometry-box keywords —
border-box,padding-box,content-box,margin-box,fill-box,stroke-box,view-box. These can be used alone or combined with a basic shape.
Here are the most common mistakes that cause this error:
- Missing units on length values. Writing
circle(50 at 50% 50%)is invalid because50needs a unit likepx,em, or%. The value0is the only length that doesn't require a unit. - Wrong separators. In
circle()andellipse(), the position coordinates afteratmust be separated by spaces, not commas. Inpolygon(), each coordinate pair uses a space between x and y, while commas separate the points from each other. - Malformed
path()data. The SVG path string insidepath()must be wrapped in quotes, e.g.,path("M0 0 L100 0 L100 100 Z"). - Typos or unsupported functions. Using a function name the specification doesn't define, or misspelling one like
cirlce(), will trigger the error. - Invalid
polygon()fill-rule. If you specify a fill rule inpolygon(), it must benonzeroorevenodd, followed by a comma before the first point.
Getting clip-path syntax right matters for standards compliance and cross-browser consistency. Browsers may silently ignore an invalid clip-path value, meaning your intended visual effect simply won't appear — and you may not realize why. Validating your CSS catches these issues early.
Here is a quick reference for the correct syntax of each basic shape function:
circle(<radius> at <cx> <cy>)— Radius is a length or percentage. Position uses spaces, not commas.ellipse(<rx> <ry> at <cx> <cy>)— Both radii are lengths or percentages.inset(<top> <right> <bottom> <left> round <border-radius>)— Offsets are lengths or percentages. Theroundkeyword and border-radius are optional.polygon([<fill-rule>,] <x1> <y1>, <x2> <y2>, ...)— Space between x and y within a point; comma between points.path("<SVG path data>")— Path data string must be quoted.
Examples
Invalid clip-path values
<style>
/* Invalid: unitless radius; comma between position coordinates */
.clip-a{
clip-path:circle(50 at 50%,50%);
}
/* Invalid: commas between x and y within each point */
.clip-b{
clip-path:polygon(0%,0%,100%,0%,100%,100%,0%,100%);
}
/* Invalid: path data not wrapped in quotes */
.clip-c{
clip-path:path(M0 0 L100 0 L100 100 Z);
}
/* Invalid: misspelled function name */
.clip-d{
clip-path:cirlce(50% at 50%50%);
}
</style>
Valid clip-path values
<style>
/* Valid circle: radius has a unit; position uses spaces */
.clip-a{
clip-path:circle(50px at 50%50%);
}
/* Valid polygon: space between x and y, commas between points */
.clip-b{
clip-path:polygon(0%0%,100%0%,100%100%,0%100%);
}
/* Valid path: SVG data is quoted */
.clip-c{
clip-path:path("M0 0 L100 0 L100 100 Z");
}
/* Valid inset with rounded corners */
.clip-d{
clip-path:inset(10%20%10%20% round 8px);
}
/* Valid geometry-box keyword combined with a shape */
.clip-e{
clip-path: padding-box circle(50% at 50%50%);
}
/* Valid: referencing an SVG clipPath */
.clip-f{
clip-path:url(#roundClip);
}
</style>
Full example with SVG <clipPath> reference
<!doctype html>
<htmllang="en">
<head>
<title>Valid clip-path with SVG reference</title>
<style>
.clipped{
clip-path:url(#roundClip);
width:200px;
height:200px;
background: coral;
}
</style>
</head>
<body>
<svgwidth="0"height="0"aria-hidden="true">
<clipPathid="roundClip"clipPathUnits="objectBoundingBox">
<circlecx="0.5"cy="0.5"r="0.5"></circle>
</clipPath>
</svg>
<divclass="clipped">Clipped element</div>
</body>
</html>
When you encounter this validation error, carefully check the value reported in the error message. Compare it against the accepted syntax for the function you're using, paying close attention to units, separators, and quoting. Small syntax differences — a comma where a space should be, or a missing unit — are the most frequent culprits.
The font-size property defines the size of text in CSS and accepts a specific set of value types. When the W3C validator reports that a value "is not a font-size value," it means the value you provided doesn't match any of the accepted formats. Browsers may attempt to ignore or guess what you meant, but this leads to unpredictable rendering across different browsers and devices.
This error commonly occurs for a few reasons:
- Missing units on numeric values. Writing
font-size: 16instead offont-size: 16px. In CSS, unitless numbers (other than0) are not valid lengths. - Typos in units or keywords. For example,
font-size: 16xp,font-size: 1.2erm, orfont-size: lage. - Using values from the wrong property. For example,
font-size: bold(which belongs tofont-weight) orfont-size: center. - Invalid or unsupported syntax. For example,
font-size: 16 px(with a space between the number and unit) orfont-size: auto(which is not valid for this property).
Valid font-size value types
| Type | Examples | Notes |
|---|---|---|
| Absolute keywords | xx-small, x-small, small, medium, large, x-large, xx-large, xxx-large | Browser-defined sizes |
| Relative keywords | smaller, larger | Relative to the parent element's font size |
| Length units | 16px, 1.2em, 0.9rem, 12pt, 1vw | Must include a unit (except 0) |
| Percentages | 100%, 120%, 80% | Relative to the parent element's font size |
| Math functions | calc(1rem + 2px), clamp(1rem, 2vw, 3rem) | CSS math expressions that resolve to a length |
Examples
Incorrect: missing unit on a number
<pstyle="font-size:16;">This triggers a validation error.</p>
The value 16 is not valid because it lacks a CSS unit. Browsers may ignore this declaration entirely, leaving the text at its default or inherited size.
Correct: number with a valid unit
<pstyle="font-size:16px;">This text has a valid font size.</p>
Incorrect: typo in the unit
<pstyle="font-size:1.2erm;">Typo in the unit.</p>
Correct: proper em unit
<pstyle="font-size:1.2em;">Correct em unit.</p>
Incorrect: value from the wrong property
<pstyle="font-size: bold;">Bold is not a font-size value.</p>
Correct: using a valid keyword
<pstyle="font-size: large;">Using a valid size keyword.</p>
Incorrect: space between number and unit
<pstyle="font-size:16 px;">Space before the unit is invalid.</p>
Correct: no space between number and unit
<pstyle="font-size:16px;">No space between number and unit.</p>
Full document example
<!DOCTYPE html>
<htmllang="en">
<head>
<title>Font Size Example</title>
<style>
.heading{
font-size:2rem;
}
.body-text{
font-size:1em;
}
.small-print{
font-size:80%;
}
.responsive{
font-size:clamp(1rem,2.5vw,2rem);
}
</style>
</head>
<body>
<h1class="heading">Valid heading size</h1>
<pclass="body-text">Body text at 1em.</p>
<pclass="small-print">Small print at 80%.</p>
<pclass="responsive">Responsive text using clamp().</p>
</body>
</html>
To resolve this validation error, review every font-size declaration in your CSS or inline styles. Make sure each value is either a recognized keyword, a number immediately followed by a valid unit, a percentage, or a supported CSS function like calc(). If you intended 0, that is the one numeric value that does not require a unit — font-size: 0 is valid, though rarely useful in practice.
The aspect-ratio CSS property defines the preferred width-to-height ratio of an element's box. Browsers use this ratio when calculating auto sizes and performing other layout functions, adjusting the element's dimensions to maintain the specified proportion even as the parent container or viewport changes size.
The ratio is expressed as <width> / <height>. If the slash and height portion are omitted, height defaults to 1. So aspect-ratio: 2 is equivalent to aspect-ratio: 2 / 1. The property also accepts the auto keyword, which tells the element to use its intrinsic aspect ratio (if it has one), and a combined form like auto 3 / 4, which prefers the intrinsic ratio but falls back to the specified one.
This validation error typically occurs for several reasons:
- Using invalid separators or syntax, such as a colon (
:) instead of a slash (/), e.g.,aspect-ratio: 16:9. - Providing units, such as
aspect-ratio: 16px / 9px. The values must be unitless positive numbers. - Using zero or negative numbers, which are not valid. Both parts of the ratio must be positive (
> 0). - Providing a string or unrecognized keyword, such as
aspect-ratio: wideoraspect-ratio: "16/9". - Missing spaces around the slash, though this is less common —
16/9may work in browsers but the canonical form uses spaces:16 / 9. - Using the property in inline
styleattributes validated against an older CSS level whereaspect-ratiowasn't yet recognized by the validator.
Getting this value right matters for layout consistency across browsers. An invalid value will be ignored entirely by the browser, meaning the element won't maintain any aspect ratio, potentially breaking your design. It's especially important for responsive images, video containers, and card layouts where maintaining proportions is critical.
Examples
Incorrect: using a colon as the separator
<divstyle="aspect-ratio:16:9;width:100%;"></div>
The colon syntax (common in video specifications) is not valid CSS. The validator will reject 16:9 as an aspect-ratio value.
Incorrect: using units in the ratio
<divstyle="aspect-ratio:16px/9px;width:100%;"></div>
The ratio values must be unitless numbers. Adding px or any other unit makes the value invalid.
Incorrect: using zero in the ratio
<divstyle="aspect-ratio:0/1;width:100%;"></div>
Both numbers in the ratio must be strictly positive. Zero is not allowed.
Correct: standard ratio with a slash
<divstyle="aspect-ratio:16/9;width:100%;"></div>
Correct: single number (height defaults to 1)
<divstyle="aspect-ratio:2;width:100%;"></div>
This is equivalent to aspect-ratio: 2 / 1.
Correct: square ratio
<divstyle="aspect-ratio:1/1;width:100%;"></div>
Correct: using the auto keyword
<imgsrc="photo.jpg"alt="A landscape photo"style="aspect-ratio: auto;width:100%;">
The element uses its intrinsic aspect ratio if available.
Correct: combining auto with a fallback ratio
<imgsrc="photo.jpg"alt="A landscape photo"style="aspect-ratio: auto 4/3;width:100%;">
The browser prefers the image's intrinsic ratio, but if it hasn't loaded yet or has no intrinsic ratio, it falls back to 4 / 3. This is useful for preventing layout shift while images load.
Correct: using global CSS values
<divstyle="aspect-ratio: inherit;width:100%;"></div>
Global values like inherit, initial, unset, revert, and revert-layer are also valid.
Every HTML element has a defined set of attributes it accepts. The HTML specification maintains strict rules about which attributes belong on which elements. For example, the href attribute is valid on an <a> element but not on a <div>. The for attribute belongs on <label> and <output> elements but not on <span>. When you place an attribute on an element that doesn't recognize it, the validator flags the error.
This issue matters for several reasons. First, browsers may silently ignore unrecognized attributes, meaning your code might appear to work but isn't actually doing anything — leading to hard-to-diagnose bugs. Second, assistive technologies like screen readers rely on valid HTML to correctly interpret page structure and behavior. Invalid attributes can confuse these tools and degrade accessibility. Third, standards-compliant HTML ensures consistent behavior across all browsers and future-proofs your code.
There are several common causes of this error:
- Typos or misspellings — Writing
hieghtinstead ofheight, orscrinstead ofsrc. - Attributes on the wrong element — Using
placeholderon a<div>instead of an<input>or<textarea>. - Obsolete attributes — Using presentational attributes like
align,bgcolor, orborderthat have been removed from the HTML specification in favor of CSS. - Framework-specific attributes — Using attributes like
ng-click(Angular),v-if(Vue), or@click(Vue shorthand) that aren't part of standard HTML. These frameworks typically process them before the browser sees them, but the raw HTML won't validate. - Custom attributes without the
data-*prefix — Inventing your own attributes liketooltiporstatuswithout following thedata-*convention. - ARIA attributes with typos — Writing
aria-roleinstead of the correctrole, oraria-labelledinstead ofaria-labelledby.
Examples
Attribute used on the wrong element
The placeholder attribute is only valid on <input> and <textarea> elements:
<!-- ❌ "placeholder" not allowed on "div" -->
<divplaceholder="Enter text here">Content</div>
<!-- ✅ Use placeholder on a supported element -->
<inputtype="text"placeholder="Enter text here">
Obsolete presentational attribute
The align attribute has been removed from most elements in HTML5. Use CSS instead:
<!-- ❌ "align" not allowed on "div" -->
<divalign="center">Centered content</div>
<!-- ✅ Use CSS for presentation -->
<divstyle="text-align: center;">Centered content</div>
Custom attribute without data-* prefix
If you need to store custom data on an element, use the data-* attribute format:
<!-- ❌ "tooltip" not allowed on "span" -->
<spantooltip="More information">Hover me</span>
<!-- ✅ Use a data-* attribute for custom data -->
<spandata-tooltip="More information">Hover me</span>
The data-* attributes are specifically designed for embedding custom data. You can access them in JavaScript via the dataset property, e.g., element.dataset.tooltip.
Misspelled attribute
A simple typo can trigger this error:
<!-- ❌ "widht" not allowed on "img" -->
<imgsrc="photo.jpg"widht="300"alt="A photo">
<!-- ✅ Correct the spelling -->
<imgsrc="photo.jpg"width="300"alt="A photo">
ARIA attribute typo
ARIA attributes must match their exact specification names:
<!-- ❌ "aria-labelled" not allowed on "input" -->
<inputtype="text"aria-labelled="name-label">
<!-- ✅ Use the correct ARIA attribute name -->
<inputtype="text"aria-labelledby="name-label">
Framework-specific attributes
If you're using a JavaScript framework and want your source templates to validate, be aware that framework-specific syntax won't pass validation. In Vue, for example, you can use the data-* equivalent or accept that templates are preprocessed:
<!-- ❌ "v-if" not allowed on "div" -->
<divv-if="isVisible">Hello</div>
<!-- This is expected with Vue templates and is typically not a concern, since the framework processes these before they reach the browser. -->
since the framework processes these before they reach the browser. -->
When encountering this error, check the MDN Web Docs reference for the element in question to see which attributes it actually supports. This will quickly clarify whether you need to fix a typo, move the attribute to a different element, replace it with CSS, or convert it to a data-* attribute.
The font-size property sets the size of text and expects a valid CSS value — either a keyword (like small, medium, large), a numeric value with a unit (like 16px, 1.2em, 100%), or 0 (which needs no unit). When the validator reports that "px" is not a valid font-size value, it means the property received the string px alone, without the required number preceding it.
This issue commonly arises in a few scenarios:
- Typos or accidental deletion: The number was removed during editing, leaving just the unit behind.
- Template or CMS output: A dynamic value (e.g., from a variable or database field) resolved to empty, producing something like
font-size: px;. - Preprocessor errors: A Sass, Less, or other CSS preprocessor variable was undefined or empty, resulting in a bare unit in the compiled CSS.
While most browsers will simply ignore the invalid declaration and fall back to an inherited or default font size, this creates unpredictable rendering. The text may appear at an unexpected size, and the behavior may differ across browsers. Invalid CSS also causes W3C validation failures, which can signal deeper problems in your code or build pipeline.
How to Fix It
- Check for a missing number: Look at the
font-sizedeclaration flagged by the validator and add the intended numeric value before the unit. - Inspect dynamic values: If the value comes from a variable, template engine, or CMS field, ensure it outputs a complete value (e.g.,
16or16px) rather than an empty string. - Use a fallback: When generating CSS dynamically, consider providing a fallback value in case the variable is empty.
Examples
❌ Incorrect: Bare unit with no number
<pstyle="font-size: px;">This text has an invalid font size.</p>
The validator will report that "px" is not a valid font-size value because no number precedes the unit.
✅ Correct: Numeric value with unit
<pstyle="font-size:16px;">This text has a valid font size.</p>
❌ Incorrect: Empty value from a template variable
This is a common pattern in templating systems that can produce invalid CSS:
<pstyle="font-size: px;">Dynamic content here.</p>
When the template variable resolves to an empty string, only px remains.
✅ Correct: Using a keyword value
If you don't need a specific pixel size, CSS keywords are another valid option:
<pstyle="font-size: medium;">This uses a keyword font size.</p>
✅ Correct: Using other valid units
The font-size property accepts many unit types. All of these are valid:
<style>
.example-em{font-size:1.2em;}
.example-rem{font-size:1rem;}
.example-percent{font-size:120%;}
.example-px{font-size:14px;}
.example-keyword{font-size: large;}
</style>
✅ Correct: Full document example
<!DOCTYPE html>
<htmllang="en">
<head>
<title>Font Size Example</title>
<style>
p{
font-size:16px;
}
</style>
</head>
<body>
<p>This paragraph has a valid font size of 16px.</p>
</body>
</html>
The HTML specification defines a specific set of global attributes (like class, id, title, style, etc.) that are allowed on all elements, plus element-specific attributes for certain tags. Any attribute that isn't part of these standard sets and doesn't follow the data-* custom attribute convention is considered invalid and will trigger a validation error.
This issue is especially common with older integrations of third-party tools like ShareThis, AddThis, or similar social sharing widgets, particularly when embedded through a CMS like Drupal or WordPress. These older implementations relied on proprietary attributes such as displayText, st_url, and st_title directly on <span> or other elements. Modern versions of these tools have since migrated to valid data-* attributes.
Why This Matters
- Standards compliance: Non-standard attributes violate the HTML specification, meaning your markup is technically invalid and may behave unpredictably across browsers.
- Forward compatibility: Browsers could introduce a native
displaytextattribute in the future with entirely different behavior, causing conflicts with your code. - Accessibility: Assistive technologies rely on well-formed HTML. Non-standard attributes can confuse screen readers or other tools that parse the DOM.
- Maintainability: Using the standardized
data-*convention makes it immediately clear to other developers that an attribute holds custom data, improving code readability.
How to Fix It
- Identify all non-standard attributes on your elements (e.g.,
displayText,st_url,st_title). - Prefix each one with
data-to convert it into a valid custom data attribute (e.g.,data-displaytext,data-st-url,data-st-title). - Update any JavaScript that references these attributes. If JavaScript accesses them via
element.getAttribute('displayText'), change it toelement.getAttribute('data-displaytext')or use thedatasetAPI (element.dataset.displaytext). - If using a CMS or third-party plugin, update the plugin or module to its latest version, which likely uses valid
data-*attributes already.
Note that data-* attribute names should be all lowercase. Even if the original attribute used camelCase like displayText, the corrected version should be data-displaytext.
Examples
Invalid: Non-standard attribute on a <span>
<spanclass="st_sharethis"displaytext="ShareThis"st_url="https://example.com"st_title="My Page">
Share
</span>
This triggers validation errors for displaytext, st_url, and st_title because none of these are valid HTML attributes.
Valid: Using data-* attributes
<spanclass="st_sharethis"data-displaytext="ShareThis"data-st-url="https://example.com"data-st-title="My Page">
Share
</span>
Accessing data-* attributes in JavaScript
If your JavaScript relied on the old attribute names, update the references:
<spanid="share-btn"data-displaytext="ShareThis">Share</span>
<script>
constbtn=document.getElementById('share-btn');
// Using getAttribute
consttext=btn.getAttribute('data-displaytext');
// Using the dataset API
consttextAlt=btn.dataset.displaytext;
</script>
Valid: Using a standard attribute instead
In some cases, the intent of displaytext is simply to provide a label or tooltip. If so, a standard attribute like title may be more appropriate:
<spanclass="st_sharethis"title="ShareThis">Share</span>
Choose the approach that best matches your use case — data-* for custom data consumed by JavaScript, or a semantic HTML attribute if one already serves the purpose.
The border-color property sets the color of an element's four borders. When the W3C validator reports that a given value "is not a border-color value," it means the value you provided doesn't match any recognized CSS color format. Common mistakes that trigger this error include using a bare number like 0 instead of a color, misspelling a color keyword (e.g., grren instead of green), forgetting the # prefix on a hex code, or passing an invalid argument to a color function.
This matters because browsers handle invalid CSS values unpredictably. When a browser encounters an unrecognized border-color value, it discards the entire declaration and falls back to the inherited or initial value (typically currentcolor). This can lead to inconsistent rendering across browsers and make your design behave in unexpected ways. Writing valid CSS ensures predictable, cross-browser results and keeps your stylesheets maintainable.
Valid color formats
The CSS border-color property accepts any valid <color> value, including:
- Named keywords —
red,blue,transparent,currentcolor, etc. - Hexadecimal —
#rgb,#rrggbb,#rgba,#rrggbbaa rgb()/rgba()—rgb(255, 0, 0)orrgb(255 0 0 / 50%)hsl()/hsla()—hsl(0, 100%, 50%)orhsl(0 100% 50% / 0.5)
You can also specify one to four color values to target individual sides (top, right, bottom, left), following the standard CSS shorthand pattern.
Examples
Invalid: bare number instead of a color
A number like 0 is not a valid color value and triggers the error:
<style>
.box{
border:1px solid;
border-color:0;
}
</style>
Invalid: misspelled color keyword
Typos in color names are not recognized by CSS:
<style>
.box{
border:1px solid;
border-color: grren;
}
</style>
Invalid: hex code missing the # prefix
Without the leading #, the value is treated as an unknown keyword:
<style>
.box{
border:1px solid;
border-color: ff0000;
}
</style>
Fixed: using a named color keyword
<style>
.box{
border:1px solid;
border-color: green;
}
</style>
Fixed: using a hexadecimal value
<style>
.box{
border:1px solid;
border-color:#00ff00;
}
</style>
Fixed: using rgb() functional notation
<style>
.box{
border:1px solid;
border-color:rgb(0,128,0);
}
</style>
Fixed: using hsl() functional notation
<style>
.box{
border:1px solid;
border-color:hsl(120,100%,25%);
}
</style>
Fixed: setting different colors per side
You can provide up to four valid color values to control each border individually (top, right, bottom, left):
<style>
.box{
border:1px solid;
border-color: red green blue orange;
}
</style>
Fixed: using transparent or currentcolor
The special keywords transparent and currentcolor are also valid:
<style>
.box{
border:1px solid;
border-color: transparent;
}
.highlight{
color: navy;
border:2px solid;
border-color: currentcolor;
}
</style>
If you're unsure whether a value is a valid CSS color, check the MDN <color> data type reference for the complete list of accepted formats.
The mask-image CSS property sets one or more mask layers for an element, controlling which parts are visible based on the mask's alpha channel or luminance. According to the CSS Masking specification, the property accepts a comma-separated list of mask references, where each individual value must be one of:
none— No mask layer is applied.- A
<image>value — This includesurl()references to image files (PNG, SVG, etc.) and CSS image functions likeimage(). - A CSS gradient — Functions like
linear-gradient(),radial-gradient(),conic-gradient(), and their repeating variants (repeating-linear-gradient(), etc.).
When the validator encounters a value that doesn't match any of these accepted forms, it flags the error. This matters because browsers will silently discard invalid mask-image declarations, meaning your intended masking effect won't apply, and the element will render as if no mask were set.
Common causes
Typos in gradient or function names are a frequent trigger. For example, writing linear-gradiant() instead of linear-gradient(), or radial-grad() instead of radial-gradient().
Bare image paths without url() will also cause this error. The value mask.png is not valid on its own — it must be wrapped as url('mask.png').
Unsupported keywords or arbitrary strings like mask-image: circle or mask-image: overlay are not valid. The only keyword mask-image accepts is none.
Malformed gradient syntax such as missing parentheses, invalid color stops, or incorrect direction keywords can also produce this error. For instance, linear-gradient(right, red, blue) is invalid because directional keywords require the to prefix.
Vendor-prefixed values used without the matching prefix on the property can trigger issues as well. Using -webkit-gradient() as a value for the standard mask-image property may not validate.
Examples
Incorrect: bare image path without url()
<divstyle="mask-image: mask.png;">
Content here
</div>
Correct: image path wrapped in url()
<divstyle="mask-image:url('mask.png');">
Content here
</div>
Incorrect: typo in gradient function name
<divstyle="mask-image:linear-gradiant(to right, transparent, black);">
Content here
</div>
Correct: properly spelled gradient function
<divstyle="mask-image:linear-gradient(to right, transparent, black);">
Content here
</div>
Incorrect: missing to keyword in gradient direction
<divstyle="mask-image:linear-gradient(right, transparent, black);">
Content here
</div>
Correct: direction uses the to keyword
<divstyle="mask-image:linear-gradient(to right, transparent, black);">
Content here
</div>
Incorrect: unsupported keyword
<divstyle="mask-image: overlay;">
Content here
</div>
Correct: using none to explicitly disable masking
<divstyle="mask-image: none;">
Content here
</div>
Correct: multiple mask layers
<divstyle="mask-image:url('star.svg'),linear-gradient(to bottom, black, transparent);">
Content here
</div>
Correct: radial gradient as a mask
<divstyle="mask-image:radial-gradient(circle, black 50%, transparent 100%);">
Content here
</div>
Note that browser support for the unprefixed mask-image property has improved significantly, but some older browsers may still require the -webkit-mask-image prefix. When using the prefixed version, make sure to also include the standard property for forward compatibility. The W3C validator checks against the standard syntax, so always ensure your standard mask-image declaration uses valid values even if you also include prefixed versions.
The ontouchstart attribute is an inline event handler that some developers use to detect when a user touches an element on a touchscreen device. However, unlike standard event handler attributes such as onclick, onmousedown, or onkeydown, the ontouchstart attribute is not defined in the HTML specification. The W3C validator flags it because only attributes explicitly listed in the spec are allowed on a given element.
The touchstart event itself is a legitimate event defined in the Touch Events specification — it's the inline HTML attribute form (ontouchstart) that isn't recognized as a valid attribute by the HTML standard. This distinction is important: you can absolutely listen for touchstart events, just not via an inline attribute on an HTML element.
Why This Is a Problem
- Standards compliance: Using non-standard attributes produces invalid HTML, which can cause issues with automated testing, accessibility audits, and content management pipelines that enforce validation.
- Accessibility: Relying solely on touch events excludes users who navigate with a keyboard, mouse, or assistive technology. Touch-only handlers can make interactive elements completely inaccessible to non-touch users.
- Maintainability: Inline event handlers mix behavior with markup, making code harder to maintain and debug compared to centralized JavaScript event listeners.
- Browser inconsistencies: While most mobile browsers support the
touchstartevent, the inline attribute form is not guaranteed to work consistently across all environments.
How to Fix It
- Remove the inline
ontouchstartattribute from your HTML element. - Use
addEventListenerin JavaScript to attach thetouchstartevent listener programmatically. - Consider also handling
clickorpointerdownevents so the interaction works for all input types — mouse, keyboard, touch, and stylus. The Pointer Events API (pointerdown,pointerup, etc.) is a modern, unified approach that covers mouse, touch, and pen input in a single event model.
Examples
❌ Invalid: Inline ontouchstart attribute
<divontouchstart="handleTouch()">Tap me</div>
This triggers the validation error because ontouchstart is not a recognized attribute in the HTML specification.
✅ Valid: Using addEventListener for touchstart
<divid="touch-target">Tap me</div>
<script>
document.getElementById("touch-target").addEventListener("touchstart",function(event){
// Handle touch interaction
});
</script>
The touchstart event is attached through JavaScript, keeping the HTML valid and clean.
✅ Valid: Using Pointer Events for cross-input support
<buttonid="action-btn"type="button">Tap or click me</button>
<script>
document.getElementById("action-btn").addEventListener("pointerdown",function(event){
// Handles mouse, touch, and pen input
});
</script>
Using pointerdown instead of touchstart provides a single handler that works across all input types. Note also the use of a <button> element, which is natively focusable and accessible, making it a better choice than a <div> for interactive elements.
✅ Valid: Supporting both touch and non-touch with separate listeners
<divid="interactive-area"role="button"tabindex="0">Interact with me</div>
<script>
varel=document.getElementById("interactive-area");
el.addEventListener("touchstart",function(event){
// Handle touch-specific interaction
});
el.addEventListener("click",function(event){
// Handle mouse and keyboard interaction
});
</script>
If you must use a <div> as an interactive element, add role="button" and tabindex="0" for accessibility, and attach both touchstart and click listeners to cover all input methods.
The <table> element in HTML supports a limited set of attributes — primarily global attributes like class, id, and style. The height attribute was never part of the HTML standard for tables (unlike width, which was valid in HTML 4 but has since been deprecated). Despite this, many browsers historically accepted height on <table> as a non-standard extension, which led to its widespread but incorrect use.
Because height is not a recognized attribute on <table>, using it means your markup is invalid and may behave inconsistently across browsers. Some browsers might honor it, others might ignore it entirely, and future browser versions could change their behavior at any time. Relying on non-standard attributes makes your code fragile and harder to maintain.
The fix is straightforward: remove the height attribute from the <table> element and use CSS to set the desired height. You can apply the CSS inline via the style attribute, or better yet, use an external or internal stylesheet with a class or ID selector.
Examples
❌ Invalid: height attribute on <table>
<tableheight="300">
<tr>
<td>Name</td>
<td>Score</td>
</tr>
<tr>
<td>Alice</td>
<td>95</td>
</tr>
</table>
This triggers the validator error: Attribute "height" not allowed on element "table" at this point.
✅ Fixed: Using inline CSS
<tablestyle="height:300px;">
<tr>
<td>Name</td>
<td>Score</td>
</tr>
<tr>
<td>Alice</td>
<td>95</td>
</tr>
</table>
✅ Fixed: Using a CSS class (preferred)
<style>
.tall-table{
height:300px;
}
</style>
<tableclass="tall-table">
<tr>
<td>Name</td>
<td>Score</td>
</tr>
<tr>
<td>Alice</td>
<td>95</td>
</tr>
</table>
Using a class keeps your HTML clean and makes it easy to adjust the styling later without touching the markup. Note that min-height is often a better choice than height for tables, since table content can naturally grow beyond a fixed height, and min-height ensures the table is at least a certain size without clipping content.
The <time> element represents a specific moment or duration in time. Browsers, search engines, and assistive technologies rely on parsing its value to understand temporal data programmatically. The element can get its machine-readable value from two places: the datetime attribute, or, if that attribute is absent, from the element's text content directly.
When there is no datetime attribute, the text content itself must be in one of the valid formats specified by the HTML standard. This is where the error typically occurs—authors write a human-readable date like "March 20, 2025" or "last Tuesday" as the text content without providing a datetime attribute, and the validator rejects it because that string isn't machine-parsable.
Why This Matters
- Machine readability: Search engines (via structured data) and browser features (like calendar integration) depend on parsing the
<time>element's value. An invalid format means these tools can't understand the date or time. - Accessibility: Screen readers and other assistive technologies may use the machine-readable datetime to present temporal information more helpfully to users.
- Standards compliance: The HTML specification explicitly defines which formats are valid. Using anything else makes your document non-conforming.
How to Fix It
You have two options:
- Add a
datetimeattribute with the machine-readable value, and keep the human-readable text as the visible content. This is the most common and practical approach. - Use a valid format directly as the text content if you don't mind displaying a machine-readable format to users.
Valid Formats
Here is a reference of accepted formats for the <time> element:
| Type | Example(s) |
|---|---|
| Valid year | 2011 |
| Valid month | 2011-11 |
| Valid date | 2011-11-18 |
| Valid yearless date | 11-18 |
| Valid week | 2011-W47 |
| Valid time | 14:54, 14:54:39, 14:54:39.929 |
| Valid local date and time | 2011-11-18T14:54:39.929 or 2011-11-18 14:54:39.929 |
| Valid global date and time | 2011-11-18T14:54:39.929Z, 2011-11-18T14:54:39.929-04:00 |
| Valid duration | PT4H18M3S, P2D (2 days), P3DT4H (3 days, 4 hours) |
Examples
Incorrect: Human-readable text without datetime attribute
The validator will report the error because "March 20, 2025" is not a valid machine-readable format:
<p>The concert is on <time>March 20, 2025</time>.</p>
Incorrect: Informal text as content
Similarly, casual date strings are not valid:
<p>Updated <time>last Friday</time>.</p>
Correct: Using the datetime attribute
Add a datetime attribute with the machine-readable value and keep the human-friendly text visible:
<p>The concert is on <timedatetime="2025-03-20">March 20, 2025</time>.</p>
Correct: Including time and timezone
<p>
The event starts at
<timedatetime="2025-03-20T13:00-05:00">1:00 PM EST on March 20, 2025</time>.
</p>
Correct: Machine-readable format as text content
If no datetime attribute is provided, the text content itself must be a valid format:
<p>Date: <time>2025-03-20</time></p>
Correct: Representing a duration
<p>Cooking time: <timedatetime="PT1H30M">1 hour and 30 minutes</time>.</p>
Correct: Using just a time value
<p>The shop opens at <time>09:00</time> every day.</p>
As a general rule, whenever you want to display a date or time in a natural, human-friendly way, always pair it with a datetime attribute that contains the machine-readable equivalent. This keeps your HTML valid, your content accessible, and your temporal data useful to machines.
The aria-expanded attribute is redundant on a summary element when it is the direct child of a details element, because the browser already communicates the expanded/collapsed state through the native open attribute on details.
The summary element, when used as the first child of a details element, acts as the built-in toggle control. Assistive technologies already understand this relationship and automatically convey whether the disclosure widget is open or closed based on the details element's open attribute. Adding aria-expanded to summary in this context creates duplicate semantics, which can confuse screen readers by announcing the state twice.
If you're using JavaScript to toggle aria-expanded manually, you can safely remove it and rely on the native behavior instead. The details/summary pattern is one of the best examples of built-in accessibility that requires no extra ARIA attributes.
Incorrect Example
<details>
<summaryaria-expanded="false">More information</summary>
<p>Here are the additional details.</p>
</details>
Correct Example
<details>
<summary>More information</summary>
<p>Here are the additional details.</p>
</details>
If you need the section to be open by default, use the open attribute on the details element:
<detailsopen>
<summary>More information</summary>
<p>Here are the additional details.</p>
</details>
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