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.
All HTML documents must use UTF-8 character encoding. The shift_jis encoding is a legacy Japanese encoding that is no longer valid in modern HTML.
The HTML specification requires UTF-8 as the only permitted character encoding for HTML documents. This rule applies regardless of the document's language or the characters it contains. Legacy encodings like shift_jis, euc-jp, iso-8859-1, and others are not allowed.
To fix this, two things need to happen. First, the <meta> charset declaration must specify UTF-8. Second, the file itself must actually be saved with UTF-8 encoding. Declaring UTF-8 in the markup while the file is saved as Shift_JIS will cause garbled text (mojibake). Most modern text editors and IDEs (VS Code, Sublime Text, Notepad++) can convert a file's encoding through a "Save with Encoding" or "Reopen with Encoding" option.
If a server sends a Content-Type header with charset=shift_jis, that header also needs to be updated to charset=utf-8. The HTTP header takes precedence over the <meta> tag, so fixing only the HTML is not enough if the server overrides it.
HTML examples
Before (invalid)
<!doctype html>
<htmllang="ja">
<head>
<metacharset="shift_jis">
<title>Example</title>
</head>
<body>
<p>日本語のテキスト</p>
</body>
</html>
After (valid)
<!doctype html>
<htmllang="ja">
<head>
<metacharset="utf-8">
<title>Example</title>
</head>
<body>
<p>日本語のテキスト</p>
</body>
</html>
Make sure the file is also saved as UTF-8 in your text editor. In VS Code, click the encoding label in the bottom status bar and select "Save with Encoding" then "UTF-8".
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>
The CSS align-items property received a value the validator does not recognize, either because it is misspelled, unsupported, or used with incorrect syntax.
The align-items property controls how flex or grid items are positioned along the cross axis of their container. Valid values include stretch, flex-start, flex-end, center, baseline, start, end, self-start, self-end, and normal. Common mistakes include using justify-content values like space-between or space-around, which do not apply to align-items. Another frequent error is a typo such as centre instead of center.
When writing inline styles or <style> blocks that get validated, only recognized CSS values pass validation. The W3C validator checks CSS embedded in HTML and flags values it cannot match to the property's grammar.
Examples
Invalid usage
<divstyle="display: flex;align-items: space-between;">
<p>Item</p>
</div>
The value space-between is not valid for align-items. It belongs to justify-content or align-content.
Fixed usage
<divstyle="display: flex;align-items: center;">
<p>Item</p>
</div>
Replace the invalid value with one that align-items accepts. In this case, center vertically centers items within the flex container.
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-checked attribute is redundant on <input type="radio"> because the browser already exposes the checked state to assistive technologies through the native checked property.
Radio inputs have built-in semantics that map directly to the aria-checked state. When a radio button is selected, the browser automatically communicates that state to the accessibility tree. Adding aria-checked manually creates a conflict: the attribute could fall out of sync with the actual checked state, and it overrides the native semantics that assistive technologies already understand.
The ARIA in HTML specification explicitly prohibits aria-checked on <input type="radio">. This falls under the general principle of not using ARIA attributes to duplicate what HTML already provides natively.
If you need to create custom styled radio buttons that don't use native <input> elements, then aria-checked belongs on an element with role="radio". But when using a standard <input type="radio">, the checked attribute (or the DOM property) is all you need.
Invalid example
<label>
<inputtype="radio"name="color"value="red"aria-checked="true"checked>
Red
</label>
<label>
<inputtype="radio"name="color"value="blue"aria-checked="false">
Blue
</label>
Valid example
Remove aria-checked and rely on the native checked attribute:
<label>
<inputtype="radio"name="color"value="red"checked>
Red
</label>
<label>
<inputtype="radio"name="color"value="blue">
Blue
</label>
If you need a custom radio group without native inputs, use role="radio" with aria-checked:
<divrole="radiogroup"aria-label="Color">
<spanrole="radio"aria-checked="true"tabindex="0">Red</span>
<spanrole="radio"aria-checked="false"tabindex="-1">Blue</span>
</div>
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>
HTML has a defined set of global attributes (like class, id, title, lang, etc.) and element-specific attributes that are permitted by the specification. Any attribute that falls outside this set — such as st_url, st_title, or displayText — will trigger a validation error because the browser and the validator don't recognize it as part of the HTML standard.
The st_url attribute, along with related attributes like st_title, st_via, and displayText, originated from early versions of the ShareThis social sharing library. These were proprietary attributes that the ShareThis JavaScript would read from the DOM to configure sharing behavior. While browsers generally ignore attributes they don't understand (so the page may still appear to work), using non-standard attributes violates the HTML specification and can cause several problems:
- Standards compliance: Invalid HTML can lead to unpredictable behavior across different browsers and future browser versions.
- Accessibility: Screen readers and other assistive technologies may not handle non-standard attributes correctly, potentially causing confusion.
- Maintainability: Non-standard markup is harder for other developers to understand and maintain.
- SEO: Search engine crawlers may penalize or misinterpret pages with significant validation errors.
HTML5 introduced data-* attributes specifically to solve this problem. Any custom data you need to attach to an element can use this pattern — for example, data-st-url instead of st_url. The ShareThis library itself updated its integration to use data-* attributes in later versions, so modern implementations should already follow this pattern.
How to Fix
- Replace proprietary attributes with
data-*equivalents: Convertst_urltodata-st-url,st_titletodata-st-title,displayTexttodata-display-text, and so on. - Update your ShareThis integration: If you're using an outdated version of ShareThis (or an outdated CMS module/plugin like an old Drupal integration), update to the latest version, which uses valid HTML5 attributes.
- Check your CMS templates: If the invalid attributes are hardcoded in a theme template or a content block, update them manually.
Examples
Invalid: Proprietary attributes on a <span>
<spanclass="st_facebook_large"displayText="Facebook"st_url="https://example.com"st_title="My Page Title"></span>
<spanclass="st_twitter_large"displayText="Twitter"st_url="https://example.com"st_title="My Page Title"></span>
This markup uses st_url, st_title, and displayText, none of which are valid HTML attributes.
Valid: Using data-* attributes instead
<spanclass="st_facebook_large"data-display-text="Facebook"data-st-url="https://example.com"data-st-title="My Page Title"></span>
<spanclass="st_twitter_large"data-display-text="Twitter"data-st-url="https://example.com"data-st-title="My Page Title"></span>
By prefixing each custom attribute with data-, the markup becomes valid HTML5. Note that you may also need to update the associated JavaScript to read from these new attribute names (e.g., using element.dataset.stUrl instead of element.getAttribute('st_url')).
Valid: Modern ShareThis integration
If you're updating your ShareThis integration entirely, the modern approach uses a different markup pattern:
<divclass="sharethis-inline-share-buttons"data-url="https://example.com"data-title="My Page Title"></div>
Modern versions of the ShareThis library expect data-* attributes by default, so upgrading the library and its associated markup is the cleanest solution. Check the ShareThis documentation for the latest recommended integration approach for your platform.
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