HTML Guides
Learn how to identify and fix common HTML validation errors flagged by the W3C Validator — so your pages are standards-compliant and render correctly across every browser. Also check our Accessibility Guides.
The transform CSS property lets you rotate, scale, skew, or translate an element by modifying its coordinate space. The validator checks inline and embedded CSS for correctness, and it will flag any value it doesn't recognize as a valid transform value. Common mistakes include:
- Missing units on angles or lengths (e.g.,
rotate(45)instead ofrotate(45deg)) - Typos in function names (e.g.,
rotatee(10deg)ortranlate(10px)) - Wrong value types (e.g., using a color or a plain number where a function is expected)
- Missing commas or parentheses in function arguments
- Using non-existent functions (e.g.,
flip(180deg)is not a valid transform function) - Incorrect number of arguments (e.g.,
matrix()requires exactly 6 values)
This matters for standards compliance and predictable rendering. While browsers may silently ignore invalid transform values, the element simply won't be transformed — which can lead to subtle layout bugs that are hard to track down. Catching these errors at validation time helps you fix them before they reach users.
Examples
Invalid: missing angle unit
The rotate() function requires a value with an angle unit like deg, rad, turn, or grad.
<divstyle="transform:rotate(45);">Rotated text</div>
Fixed: adding the angle unit
<divstyle="transform:rotate(45deg);">Rotated text</div>
Invalid: typo in function name
<divstyle="transform:tranlateX(10px);">Shifted text</div>
Fixed: correcting the function name
<divstyle="transform:translateX(10px);">Shifted text</div>
Invalid: using a non-transform value
A plain number or unrelated keyword is not a valid transform value.
<divstyle="transform:200px;">Content</div>
Fixed: using a proper transform function
<divstyle="transform:translateX(200px);">Content</div>
Invalid: wrong number of arguments for matrix()
The matrix() function requires exactly six comma-separated numbers.
<divstyle="transform:matrix(1,2,3);">Content</div>
Fixed: providing all six arguments
<divstyle="transform:matrix(1,0,0,1,0,0);">Content</div>
Valid transform values reference
Here is a summary of all valid transform functions and the keyword/global values:
<style>
/* Keyword value */
.no-transform{transform: none;}
/* Translate functions */
.move-a{transform:translate(12px,50%);}
.move-b{transform:translateX(2em);}
.move-c{transform:translateY(3in);}
.move-d{transform:translateZ(2px);}
.move-e{transform:translate3d(12px,50%,3em);}
/* Rotate functions */
.spin-a{transform:rotate(0.5turn);}
.spin-b{transform:rotateX(10deg);}
.spin-c{transform:rotateY(10deg);}
.spin-d{transform:rotateZ(10deg);}
.spin-e{transform:rotate3d(1,2,3,10deg);}
/* Scale functions */
.grow-a{transform:scale(2,0.5);}
.grow-b{transform:scaleX(2);}
.grow-c{transform:scaleY(0.5);}
.grow-d{transform:scaleZ(0.3);}
.grow-e{transform:scale3d(2.5,1.2,0.3);}
/* Skew functions */
.lean-a{transform:skew(30deg,20deg);}
.lean-b{transform:skewX(30deg);}
.lean-c{transform:skewY(1.07rad);}
/* Other functions */
.depth{transform:perspective(500px);}
.matrix-2d{transform:matrix(1,0,0,1,0,0);}
.matrix-3d{transform:matrix3d(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1);}
/* Multiple functions chained together */
.combo{transform:translateX(10px)rotate(10deg)translateY(5px);}
</style>
When troubleshooting this error, look at the specific value the validator reports as invalid. Compare it against the valid functions listed above, double-check spelling, ensure all arguments have correct units, and verify that parentheses and commas are properly placed.
The validator reports “Bad value “” for attribute id on element X: An ID must not be the empty string” when any element includes an empty id attribute. Per the HTML standard, id is a global attribute used as a unique document-wide identifier. An empty identifier is not a valid value and is ignored by some features, leading to hard-to-debug issues.
This matters for accessibility and interoperability. Features that depend on IDs—fragment navigation (#target), <label for>, ARIA attributes like aria-labelledby/aria-controls, and DOM APIs such as document.getElementById()—require a non-empty, unique value. Empty IDs break these links, can degrade assistive technology output, and violate conformance, which may hide bugs across browsers.
How to fix:
- If the element doesn’t need an identifier, remove the
idattribute entirely. - If it needs one, provide a non-empty, unique value, e.g.,
id="main-content". - Ensure uniqueness across the page; each
idmust occur only once. - Use simple, predictable tokens: avoid spaces, prefer lowercase letters, digits, hyphens, and underscores (e.g.,
feature-1). While the spec allows a broad range of characters, sticking to URL- and selector-friendly characters avoids pitfalls.
Examples
Example that triggers the validator error (empty id)
<divid=""></div>
Correct: remove an unnecessary empty id
<div></div>
Correct: provide a meaningful, unique id
<sectionid="features"></section>
Problematic label association with empty id (invalid)
<labelfor="">Email</label>
<inputtype="email"id="">
Correct label–control association
<labelfor="email">Email</label>
<inputtype="email"id="email">
Correct ARIA relationship
<h2id="pricing-heading">Pricing</h2>
<sectionaria-labelledby="pricing-heading">
<p>Choose a plan.</p>
</section>
Correct fragment navigation target
<nav>
<ahref="#contact">Contact</a>
</nav>
<sectionid="contact">
<h2>Contact us</h2>
</section>
Minimal full document (validated) demonstrating proper ids
<!doctype html>
<htmllang="en">
<head>
<metacharset="utf-8">
<title>Valid IDs Example</title>
</head>
<body>
<mainid="main-content">
<h1id="page-title">Welcome</h1>
<p>Jump to the <ahref="#details">details</a>.</p>
<sectionid="details">
<h2>Details</h2>
</section>
<form>
<labelfor="email">Email</label>
<inputid="email"type="email">
</form>
</main>
</body>
</html>
A CSS padding property contains a value the validator does not recognize as valid for that property.
The padding shorthand and its longhand variants (padding-top, padding-right, padding-bottom, padding-left) accept only <length>, <percentage>, or the keyword auto (in some contexts). Common causes of this error include:
- Using an invalid unit or misspelling a unit, such as
10xpinstead of10px. - Omitting the unit on a non-zero value, such as
padding: 10instead ofpadding: 10px. - Passing a color, keyword, or other unrelated value, such as
padding: redorpadding: bold. - Including extra or misplaced values from a copy-paste error, such as
padding: 10px 20px 30px 40px 50px(five values instead of the maximum four). - Using CSS custom properties or newer syntax in an inline
styleattribute that the validator's CSS parser does not yet support.
The padding shorthand accepts one to four values, corresponding to the top, right, bottom, and left sides. Each value must be a non-negative length (like 0, 8px, 1em, 2rem) or a percentage.
HTML examples
Invalid padding value
<divstyle="padding:10xp;">Content</div>
Fixed padding value
<divstyle="padding:10px;">Content</div>
The padding shorthand property sets the padding area on all four sides of an element. It accepts one to four values, each of which must be a <length> (e.g., 10px, 1em), a <percentage>, or 0. Unlike some other CSS properties such as border, outline, or max-width, the padding property has no none keyword in its value syntax.
This is a common mistake because several CSS properties do accept none — for example, border: none, text-decoration: none, and display: none. It's natural to assume padding: none would work the same way, but the CSS specification simply doesn't define it for padding. When a browser encounters an invalid value, it ignores the declaration entirely, which means your intended styling won't be applied and the element may retain its default or inherited padding. This can lead to unexpected layout issues that are difficult to debug.
The same rule applies to the margin property — margin: none is also invalid. Use margin: 0 instead.
How to Fix It
Replace none with 0. You don't need to include a unit when the value is zero, so padding: 0 is perfectly valid and is the idiomatic way to express "no padding." You can also use 0 for individual padding properties like padding-top, padding-right, padding-bottom, and padding-left.
If you only want to remove padding on specific sides, target those sides individually rather than using the shorthand.
Examples
❌ Incorrect: Using none with padding
.card{
padding: none;
}
The validator will report: CSS: "padding": "none" is not a "padding" value. The browser will ignore this declaration.
✅ Correct: Using 0 to remove padding
.card{
padding:0;
}
✅ Correct: Removing padding on specific sides
.card{
padding-top:0;
padding-bottom:0;
}
❌ Incorrect: Using none in inline styles
<divstyle="padding: none;">Content</div>
✅ Correct: Using 0 in inline styles
<divstyle="padding:0;">Content</div>
✅ Correct: Using valid padding values
/* Single value — applies to all four sides */
.card{
padding:16px;
}
/* Two values — vertical | horizontal */
.card{
padding:10px20px;
}
/* Four values — top | right | bottom | left */
.card{
padding:10px20px15px5px;
}
/* Zero on top/bottom, 1em on left/right */
.card{
padding:01em;
}
none is a valid value for the CSS animation shorthand property, but the W3C CSS validator sometimes flags it incorrectly depending on the CSS level it checks against.
The animation shorthand property accepts none as a value for its animation-name component. According to the CSS Animations Level 1 specification, none means no animation is applied. The shorthand combines up to eight individual properties: animation-name, animation-duration, animation-timing-function, animation-delay, animation-iteration-count, animation-direction, animation-fill-mode, and animation-play-state.
The W3C CSS validator can produce false positives for certain shorthand values. When you write animation: none, every major browser interprets it correctly as "no animation." The validator's warning does not indicate an actual problem in your CSS.
There are two ways to address this: ignore the warning since it is a known validator limitation, or use the longhand property animation-name: none instead, which the validator accepts without complaint.
Examples
Flagged by the validator
<divstyle="animation: none;">No animation here</div>
Using the longhand property to avoid the warning
<divstyle="animation-name: none;">No animation here</div>
Both produce the same result in browsers. The longhand form simply avoids the false positive from the validator.
CSS length values must always pair a number with a unit — writing just px, em, %, or any other unit without a preceding number is meaningless to the browser and will be ignored. This typically happens due to a typo, a copy-paste error, or a build tool / template that outputs a unit without its corresponding numeric value (e.g., a variable that resolved to an empty string concatenated with px).
When the W3C validator encounters margin: px in an inline style attribute, it flags the error because px on its own does not match any valid CSS value for the margin property. Valid values include lengths like 10px or 2em, percentages like 5%, the keyword auto, or the number 0 (which doesn't need a unit). Browsers will discard the invalid declaration, meaning your intended spacing won't be applied — potentially breaking your layout in subtle ways that are hard to debug.
This issue also applies to other CSS properties that accept length values, such as padding, width, height, top, left, border-width, font-size, and many more. The fix is always the same: ensure every unit has an accompanying number.
How to Fix It
- Add the missing number before the unit: change
pxto something like10px,1.5em, or20%. - Use
0without a unit if you want zero margin — writingmargin: 0is valid and preferred overmargin: 0px. - Use a keyword if appropriate, such as
margin: autofor centering. - Remove the declaration if the margin value was unintentional or unnecessary.
If the value comes from a preprocessor, template engine, or JavaScript, check that the variable being interpolated is not empty or undefined before it gets concatenated with the unit string.
Examples
Incorrect: Unit Without a Number
<divstyle="margin: px;">Content</div>
The value px has no number, so this is invalid CSS.
Correct: Number Paired With Unit
<divstyle="margin:10px;">Content</div>
Correct: Zero Margin (No Unit Needed)
<divstyle="margin:0;">Content</div>
Correct: Using a Keyword
<divstyle="margin: auto;">Content</div>
Incorrect in an External Stylesheet
This same error can appear in a <style> block or linked stylesheet:
<style>
.card{
margin: px;
}
</style>
Correct in an External Stylesheet
<style>
.card{
margin:16px;
}
</style>
Watch Out for Template Variables
A common cause in templating systems is an empty variable:
<!-- If spacing is empty, this produces "margin: px;" -->
<divstyle="margin:{{ spacing }}px;">Content</div>
To prevent this, ensure the variable contains the full value including the number, or add a fallback:
<divstyle="margin:16px;">Content</div>
The CSS cursor property controls the appearance of the mouse pointer when it hovers over an element. The value hand was introduced by early versions of Internet Explorer (IE 5.5 and earlier) as a proprietary extension to show a pointing-hand cursor over clickable elements. However, this value was never part of any CSS specification, and no other browser adopted it. The W3C-standard equivalent is pointer, which has been supported by all browsers — including Internet Explorer 6 and later — for over two decades.
When the W3C validator encounters cursor: hand, it flags it as an invalid value because hand does not exist in the CSS specification's list of accepted cursor values. While some legacy browsers may still interpret it, modern browsers will simply ignore the invalid declaration, meaning your clickable elements won't display the expected hand cursor for many users.
Beyond validation, using non-standard CSS values can cause inconsistent behavior across browsers and platforms. The pointer value is universally supported and is the correct way to signal that an element is interactive, such as a link, button, or any custom clickable region.
To fix this issue, replace every instance of cursor: hand with cursor: pointer in your stylesheets. If you need to support extremely old versions of Internet Explorer (IE 5.5 or earlier), you can declare both values — the browser will use whichever it recognizes — though this is almost never necessary today.
Examples
Invalid CSS
The value hand is not recognized by the CSS specification and will trigger a validation error:
.clickable{
cursor: hand;
}
Valid CSS
Use the standard pointer value instead:
.clickable{
cursor: pointer;
}
Using it in context with HTML
<style>
.card{
padding:16px;
border:1px solid #ccc;
cursor: pointer;
}
</style>
<divclass="card">
Click me to view details
</div>
Legacy fallback (rarely needed)
If for some reason you must support IE 5.5 or earlier alongside modern browsers, you can provide both declarations. The browser will apply the last value it understands:
.clickable{
cursor: hand;
cursor: pointer;
}
Note that this fallback pattern will still produce a validation warning for the hand value. In practice, there is virtually no reason to support browsers this old, so using cursor: pointer alone is the recommended approach.
Common cursor values
For reference, here are some of the most frequently used valid cursor values defined in the CSS specification:
auto— the browser determines the cursor based on context (default behavior)default— the platform's default cursor, typically an arrowpointer— a pointing hand, indicating a link or clickable elementtext— an I-beam, indicating selectable textmove— indicates something can be movednot-allowed— indicates an action is not permittedgrab/grabbing— indicates a draggable elementcrosshair— a precise selection cursorwait— indicates the program is busyhelp— indicates help is available
The full list of accepted values is defined in the CSS Basic User Interface Module specification.
An invalid value was assigned to the CSS right property, meaning the validator does not recognize the value you provided.
The CSS right property specifies the horizontal offset of a positioned element from the right edge of its containing block. It only accepts specific value types: a length (e.g., 10px, 2em), a percentage (e.g., 50%), auto, inherit, initial, unset, or revert. Any other value — such as a typo, a missing unit, or an unsupported keyword — will trigger this validation error.
A common mistake is forgetting the unit after a number. In CSS, 0 is the only length value that can be written without a unit. Writing something like right: 10 instead of right: 10px is invalid. Another common cause is using an unrecognized keyword or passing a value meant for a different property.
Invalid Example
<divstyle="position: absolute;right:10;">
This box has an invalid right value.
</div>
The value 10 is missing a unit, so the validator rejects it.
Fixed Example
<divstyle="position: absolute;right:10px;">
This box is correctly positioned.
</div>
Adding a valid unit like px, em, rem, or % resolves the issue. If you intended no offset, use right: 0 or right: auto.
The padding property accepts one or more length values, percentages, or the keyword 0. A valid length value always consists of a number immediately followed by a unit identifier, such as 10px, 1.5em, or 2rem. Writing just px without a preceding number is meaningless to the CSS parser — it's like saying "pixels" without specifying how many. The browser will discard the invalid declaration entirely, which means the element will fall back to its default or inherited padding, potentially breaking your layout in unexpected ways.
This error commonly occurs due to:
- Typos or accidental deletion — the numeric part of the value was inadvertently removed during editing.
- Templating or build tool issues — a dynamic value (e.g., from a variable or CMS field) resolved to an empty string, leaving only the
pxsuffix behind. - Copy-paste mistakes — copying a snippet and forgetting to update the placeholder value.
Because the W3C validator flags this in inline style attributes, it means invalid CSS is embedded directly in your HTML. Fixing it improves standards compliance and ensures consistent rendering across browsers.
How to Fix
- Add a numeric value before the unit: change
pxto something like10px,1em, or5%. - Use
0without a unit if you want zero padding — writingpadding: 0;is valid and preferred overpadding: 0px;. - Check dynamic values — if the number comes from a variable or template expression, make sure it outputs a valid number and isn't empty.
Examples
Incorrect: Unit Without a Number
<divstyle="padding: px;">Content</div>
The validator reports that px is not a valid padding value because no number precedes the unit.
Correct: Numeric Value With Unit
<divstyle="padding:10px;">Content</div>
Correct: Zero Padding (No Unit Needed)
<divstyle="padding:0;">Content</div>
When the value is 0, no unit is required since zero pixels, zero ems, and zero percent are all identical.
Correct: Multiple Padding Values
<divstyle="padding:8px16px;">Content</div>
This sets 8px of vertical padding and 16px of horizontal padding — both are valid length values.
Incorrect in External CSS
The same problem can appear in a stylesheet linked from your HTML:
.card{
padding: px;
}
Fixed in External CSS
.card{
padding:12px;
}
Watch for Template-Generated Values
If you use a templating system, double-check that the numeric portion actually renders. For example, a template like this could produce the error if spacing is empty:
<!-- If spacing is empty, this becomes "padding: px;" -->
<divstyle="padding:{{ spacing }}px;">Content</div>
Make sure the variable always resolves to a valid number, or provide a fallback value.
The CSS filter property accepts a specific set of filter functions defined in the CSS Filter Effects Module. When the validator encounters a value it doesn't recognize — such as the legacy IE progid:DXImageTransform.Microsoft. syntax, a made-up function name, or an incorrectly formatted value — it flags it as invalid.
The standard filter functions are: blur(), brightness(), contrast(), drop-shadow(), grayscale(), hue-rotate(), invert(), opacity(), saturate(), sepia(), and url() (for referencing SVG filters). The property also accepts the keyword none. Any value outside this set will trigger the validation error.
Why this matters
Using non-standard filter values creates several problems:
- Browser compatibility: Legacy or proprietary filter syntax (such as Microsoft's
filter: alpha(opacity=50)orfilter: FlipH) only works in old versions of Internet Explorer and is ignored by all modern browsers. - Standards compliance: Invalid CSS can cause parsers to discard the entire declaration or even the surrounding rule block, potentially breaking other styles.
- Future-proofing: Non-standard values may stop working entirely as browsers drop legacy support, leaving your design broken with no fallback.
How to fix it
- Identify the invalid value in the error message.
- Determine what visual effect you're trying to achieve.
- Replace the invalid value with the corresponding standard CSS
filterfunction. - If you're using legacy IE opacity filters, switch to the standard
opacityproperty instead.
Examples
❌ Invalid: Legacy Microsoft filter syntax
<style>
.overlay{
filter:alpha(opacity=50);
}
</style>
✅ Fixed: Use standard opacity property
<style>
.overlay{
opacity:0.5;
}
</style>
❌ Invalid: Misspelled or non-existent filter function
<style>
.photo{
filter:gray();
}
</style>
✅ Fixed: Use the correct grayscale() function
<style>
.photo{
filter:grayscale(100%);
}
</style>
❌ Invalid: Vendor-prefixed or proprietary value
<style>
.card{
filter: progid:DXImageTransform.Microsoft.Blur(pixelradius=5);
}
</style>
✅ Fixed: Use the standard blur() function
<style>
.card{
filter:blur(5px);
}
</style>
❌ Invalid: Bare value without a function
<style>
.image{
filter:50%;
}
</style>
✅ Fixed: Wrap the value in the appropriate function
<style>
.image{
filter:brightness(50%);
}
</style>
Combining multiple filters
You can chain multiple standard filter functions in a single declaration by separating them with spaces:
<style>
.hero-image{
filter:contrast(120%)brightness(90%)blur(1px);
}
</style>
If none of the built-in filter functions achieve the effect you need, you can reference a custom SVG filter using the url() function, which is also a valid filter value:
<svgxmlns="http://www.w3.org/2000/svg"class="visually-hidden">
<filterid="custom-effect">
<feColorMatrixtype="matrix"values="0.3 0.3 0.3 0 0 0.3 0.3 0.3 0 0 0.3 0.3 0.3 0 0 0 0 0 1 0"/>
0.3 0.3 0.3 0 0
0.3 0.3 0.3 0 0
0 0 0 1 0
</filter>
</svg>
<style>
.filtered{
filter: url(#custom-effect);
}
</style>
Negative values for the CSS border property (specifically border-width) are not valid and will be rejected by browsers.
The border-width property only accepts non-negative length values (like 1px, 0.5em) or keyword values (thin, medium, thick). A negative value such as -1px doesn't make sense for a border since you can't have a border with negative thickness.
This error often appears when using inline styles or embedded <style> blocks. It can result from a typo, a calculation error, or a misunderstanding of how border works.
If you're trying to remove a border, use border: none or border-width: 0 instead of a negative value.
Incorrect Example
<divstyle="border:-1px solid black;">
This has an invalid negative border width.
</div>
Correct Example
<!-- Using a valid positive border width -->
<divstyle="border:1px solid black;">
This has a valid border.
</div>
<!-- Removing the border entirely -->
<divstyle="border: none;">
This has no border.
</div>
The CSS width property contains an invalid value.
The width property accepts specific types of values: lengths (like 100px, 10em, 5rem), percentages (50%), viewport units (100vw), the keyword auto, and sizing keywords like max-content, min-content, or fit-content. The validator rejects anything that doesn't match these formats.
Common mistakes that trigger this error:
- Missing a unit:
width: 100instead ofwidth: 100px. Plain numbers (other than0) are not valid CSS lengths. - Using an invalid unit or typo:
width: 100 px(with a space),width: 100ppx. - Passing a non-length value:
width: red,width: bold,width: none. The keywordnoneworks formax-widthbut not forwidth. - Including extra characters:
width: 100px;50pxorwidth: 100px !importnt.
Invalid example
<divstyle="width: 600">
<p>This box has no unit on its width value.</p>
</div>
The value 600 is not valid because it lacks a CSS unit.
Fixed example
<divstyle="width: 600px">
<p>This box now has a valid width.</p>
</div>
Adding px (or another appropriate unit like em, %, rem, vw) makes the value valid. If the intent is to let the element size itself naturally, use width: auto instead.
CSS math functions like calc(), min(), max(), and clamp() follow strict rules about how operands and operators interact. The error "one operand must be a number" most commonly fires in two scenarios: either an operand is missing entirely (e.g., calc(100% - )), or both operands in a multiplication or division carry units (e.g., calc(10px * 5px)). The CSS Values and Units specification requires that for * (multiplication), at least one side must be a unitless <number>. For / (division), the right-hand side must always be a unitless <number>. You cannot multiply two lengths together or divide a length by another length within calc().
This matters for several reasons. Browsers will discard the entire property declaration if the calc() expression is invalid, which can cause layout breakage or fallback to unexpected default values. The W3C validator catches these errors in inline style attributes and embedded <style> blocks, helping you identify expressions that will silently fail in production. Fixing these issues ensures predictable rendering across all browsers.
How the rules work
- Addition and subtraction (
+,-): Both operands must have compatible types (e.g., both lengths, or both percentages, or a mix of length and percentage). Both must be present. - Multiplication (
*): At least one operand must be a plain<number>(unitless). You can writecalc(10px * 3)orcalc(3 * 10px), but notcalc(10px * 5px). - Division (
/): The right-hand operand must be a plain<number>(unitless and non-zero). You can writecalc(100px / 2), but notcalc(100px / 2px).
Examples
Missing operand
A common mistake is leaving out a value on one side of an operator:
<!-- ❌ Wrong: missing operand after the minus sign -->
<divstyle="width:calc(100%-);"></div>
<!-- ✅ Fixed: both operands are present -->
<divstyle="width:calc(100%-50px);"></div>
Multiplying two values with units
You cannot multiply two unit-bearing values together, because the result would be a meaningless type like "px²":
<!-- ❌ Wrong: both operands have units -->
<divstyle="width:calc(10px*5px);"></div>
<!-- ✅ Fixed: one operand is a unitless number -->
<divstyle="width:calc(10px*5);"></div>
Dividing by a value with units
The divisor in a / operation must be a unitless number:
<!-- ❌ Wrong: dividing by a value with units -->
<divstyle="height:calc(500px/2em);"></div>
<!-- ✅ Fixed: divisor is a unitless number -->
<divstyle="height:calc(500px/2);"></div>
Nested calc() with a missing value
Errors can hide inside nested expressions:
<!-- ❌ Wrong: inner calc has an incomplete expression -->
<pstyle="margin-top:calc(2rem+calc(100%*));"></p>
<!-- ✅ Fixed: all operands are present and valid -->
<pstyle="margin-top:calc(2rem+calc(100%*0.5));"></p>
Using variables or keywords where a number is expected
Sometimes a typo or misunderstanding leads to a non-numeric token where a number is required:
<!-- ❌ Wrong: "auto" is not a valid operand in calc() -->
<divstyle="width:calc(auto *2);"></div>
<!-- ✅ Fixed: use a numeric value or percentage -->
<divstyle="width:calc(100%*2);"></div>
To resolve this error, review every calc(), min(), max(), and clamp() expression in your inline styles and stylesheets. Confirm that all operators have valid operands on both sides, that * always has at least one unitless number, and that / always has a unitless number on the right. If you're building expressions dynamically (e.g., via JavaScript or a templating engine), double-check that variables are being interpolated correctly and not producing empty or invalid values.
Character references are how HTML represents special characters that would otherwise be interpreted as markup or that aren't easily typed on a keyboard. They come in three forms:
- Named references like
&,<,© - Decimal numeric references like
<,© - Hexadecimal numeric references like
<,©
All three forms share the same structure: they begin with & and must end with ;. When you omit the trailing semicolon, the HTML parser enters error recovery mode. Depending on the context, it may still resolve the reference (browsers are lenient), but this behavior is not guaranteed and varies across situations. For example, © without a semicolon might still render as ©, but ¬it could be misinterpreted as the ¬ (¬) reference followed by it, producing unexpected output like "¬it" instead of the literal text "¬it".
Why this matters
- Unpredictable rendering: Without the semicolon, browsers use heuristic error recovery that can produce different results depending on surrounding text. What looks fine today might break with different adjacent characters.
- Standards compliance: The WHATWG HTML specification requires the semicolon terminator. Omitting it is a parse error.
- Maintainability: Other developers (or future you) may not realize the ampersand was intended as a character reference, making the code harder to read and maintain.
- Data integrity: In URLs within
hrefattributes, a missing semicolon on a character reference can corrupt query parameters and produce broken links.
How to fix it
- Add the missing semicolon to the end of every character reference.
- If you meant a literal ampersand, use
&instead of a bare&. This is especially common in URLs with query strings. - Search your document for patterns like
&somethingwithout a trailing;to catch all instances.
Examples
❌ Missing semicolon on named references
<p>5 < 10 and 10 > 5</p>
<p>© 2024 All rights reserved</p>
✅ Properly terminated named references
<p>5 < 10 and 10 > 5</p>
<p>© 2024 All rights reserved</p>
❌ Missing semicolon on numeric references
<p>The letter A: A</p>
<p>Hex example: A</p>
✅ Properly terminated numeric references
<p>The letter A: A</p>
<p>Hex example: A</p>
❌ Bare ampersand in a URL (common mistake)
<ahref="https://example.com/search?name=alice&age=30">Search</a>
Here the validator sees &age and tries to interpret it as a character reference without a semicolon.
✅ Escaped ampersand in a URL
<ahref="https://example.com/search?name=alice&age=30">Search</a>
❌ Ambiguous reference causing wrong output
<p>The entity ¬it; doesn't exist, but ¬ without a semicolon resolves to ¬</p>
✅ Use & when you want a literal ampersand
<p>The text &notit is displayed literally when properly escaped.</p>
A quick rule of thumb: every & in your HTML should either be the start of a complete, semicolon-terminated character reference, or it should itself be written as &.
The border shorthand property accepts up to three values: a width (e.g., 1px), a style (e.g., solid), and a color (e.g., black). When the validator encounters "undefined" in the color position, it rightfully rejects it because undefined is not a recognized CSS color keyword, hex value, or color function.
This issue most commonly appears in projects that use JavaScript to dynamically set inline styles. When a variable intended to hold a color value is undefined—perhaps because it wasn't initialized, a configuration value is missing, or a function didn't return a result—the rendered HTML ends up with a literal style="border: 1px solid undefined" in the markup. Build tools, templating engines, or server-side rendering can also produce this output if a variable isn't properly resolved.
Beyond failing validation, this is a real problem because browsers will discard the entire border declaration when they encounter an invalid value. This means the border won't render at all, which may break your layout or visual design in ways that are hard to debug. Ensuring valid CSS values keeps your styling predictable across all browsers.
How to fix it
- Check for dynamic values. If the color is set via JavaScript or a templating engine, ensure the variable always resolves to a valid color string. Add fallback values or default assignments.
- Replace the invalid value. Substitute
undefinedwith a proper CSS color — a named color (red,black), a hex code (#333), anrgb()orhsl()function, or eventransparentorcurrentcolor. - Remove the declaration. If no border is needed, remove the
borderproperty entirely rather than leaving an invalid value in place.
Examples
Incorrect: literal undefined as a color value
<divstyle="border:1px solid undefined;">Content</div>
The validator rejects undefined because it is not a valid CSS color.
Incorrect: JavaScript producing undefined in markup
<script>
constborderColor=undefined;// missing configuration
document.getElementById("box").style.border="2px dashed "+borderColor;
</script>
This produces border: 2px dashed undefined on the element.
Correct: using a valid color value
<divstyle="border:1px solid black;">Content</div>
Correct: using a hex code or rgb() function
<divstyle="border:2px dashed #ff6600;">Content</div>
<divstyle="border:3px dotted rgb(0,128,255);">Content</div>
Correct: providing a fallback in JavaScript
<divid="box">Content</div>
<script>
constborderColor=getUserColor()||"#333";
document.getElementById("box").style.border="2px solid "+borderColor;
</script>
By using || "#333", you ensure a valid color is always applied even when getUserColor() returns undefined.
Correct: using separate border properties
If you prefer more granular control, you can define each border sub-property individually:
<divstyle="border-width:1px;border-style: solid;border-color: black;">Content</div>
Valid border shorthand reference
The border shorthand follows this pattern:
selector{
border: <width> <style> <color>;
}
- Width:
1px,2px,thin,medium,thick - Style:
solid,dashed,dotted,double,groove,ridge,inset,outset,none - Color: any valid CSS color — named colors (
red,blue), hex (#000),rgb(),hsl(),currentcolor, ortransparent
All three values are optional in the shorthand, but any value you do include must be valid. The string undefined is never a valid CSS value. If your styles are generated dynamically, always validate or sanitize the output before it reaches the HTML.
The color property, along with properties like background-color, border-color, and outline-color, expects values that conform to the CSS Color specification. The validator triggers this error when it encounters something that doesn't match any valid color syntax. Common causes include:
- Plain numbers like
0or123— numbers alone aren't colors. - Typos in color keywords such as
greaninstead ofgreen, ortrasparentinstead oftransparent. - Malformed hex values like
#GGG(invalid hex characters) or#12345(wrong number of digits — hex colors must be 3, 4, 6, or 8 digits). - Incorrect function syntax such as
rgb(255 255 255 / 50)missing the%on the alpha value, or using legacy commas mixed with modern space-separated syntax. - Missing units or hash symbols like
000000instead of#000000.
This matters because browsers handle invalid color values unpredictably. Most will simply ignore the declaration entirely, which means the element inherits its color from a parent or falls back to the browser default — potentially making text unreadable against its background. Writing valid CSS ensures consistent rendering across all browsers and improves the maintainability of your code.
Valid CSS color formats
CSS supports several color formats:
| Format | Example | Notes |
|---|---|---|
| Named colors | red, blue, transparent | 148 predefined keywords |
| Hexadecimal | #ff0000, #f00 | 3, 4, 6, or 8 digits |
rgb() / rgba() | rgb(255, 0, 0) | Comma or space-separated |
hsl() / hsla() | hsl(0, 100%, 50%) | Hue, saturation, lightness |
currentcolor | currentcolor | Inherits the current color value |
Examples
Invalid: plain number as a color
A bare number is not a recognized color value:
<style>
.example{
color:0;
}
</style>
Invalid: typo in a color keyword
<style>
.example{
background-color: trasparent;
}
</style>
Invalid: hex value missing the # prefix
<style>
.example{
color:000000;
}
</style>
Invalid: hex value with wrong digit count
<style>
.example{
color:#12345;
}
</style>
Fixed: using a named color keyword
<style>
.example{
color: black;
}
</style>
Fixed: using a hexadecimal color
<style>
.example{
color:#000000;
}
</style>
Fixed: using rgb()
<style>
.example{
color:rgb(0,0,0);
}
</style>
Fixed: using hsl()
<style>
.example{
color:hsl(0,0%,0%);
}
</style>
Fixed: using rgba() for semi-transparent color
<style>
.example{
color:rgba(0,0,0,0.5);
}
</style>
Fixed: correcting the transparent keyword typo
<style>
.example{
background-color: transparent;
}
</style>
If you're unsure whether a value is valid, browser DevTools can help — most browsers will strike through or ignore invalid property values in the Styles panel, giving you a quick visual indicator of the problem.
The CSS display property controls how an element generates boxes in the layout. It determines whether an element behaves as a block-level or inline-level element and defines the layout model for its children (e.g., flow, flexbox, or grid). Because display is fundamental to page layout, using an invalid value means the browser will ignore the declaration entirely, potentially causing unexpected rendering.
Common causes of this error include:
- Typos — writing
dipslay: block,display: blok, ordisplay: flxinstead of the correct keywords. - Confusing values from other properties — using values like
center,hidden,absolute, orrelative, which belong to properties liketext-align,visibility, orposition, notdisplay. - Invented or outdated values — using non-standard or deprecated values that browsers don't recognize, such as
display: box(an old prefixed flexbox syntax without the prefix). - Missing vendor prefixes — some older syntaxes like
-webkit-flexwere valid in certain browsers but are not standard CSS values.
The valid values for display include: block, inline, inline-block, flex, inline-flex, grid, inline-grid, flow-root, none, contents, table, table-row, table-cell, table-caption, table-column, table-column-group, table-footer-group, table-header-group, table-row-group, list-item, and the multi-keyword syntax like block flow, block flex, or inline grid.
Using invalid CSS values is a problem because browsers silently discard declarations they don't understand. This means your intended layout won't be applied, and debugging can be difficult since no visible error appears in the browser. Validating your CSS catches these mistakes early.
Examples
Invalid: typo in the display value
<divstyle="display: flx;">
<p>This container was meant to be a flex container.</p>
</div>
Fixed: correct flex value
<divstyle="display: flex;">
<p>This container is now a flex container.</p>
</div>
Invalid: using a value from another property
<navstyle="display: center;">
<ahref="/">Home</a>
</nav>
The value center does not belong to display. If the goal is to center content, use a valid display value combined with appropriate alignment properties.
Fixed: using flex with centering
<navstyle="display: flex;justify-content: center;">
<ahref="/">Home</a>
</nav>
Invalid: using a position value instead of a display value
<divstyle="display: absolute;">
<p>Overlay content</p>
</div>
Fixed: using the correct property
<divstyle="position: absolute;display: block;">
<p>Overlay content</p>
</div>
Invalid: using a non-standard value
<ulstyle="display: box;">
<li>Item 1</li>
<li>Item 2</li>
</ul>
Fixed: using the standard flexbox value
<ulstyle="display: flex;">
<li>Item 1</li>
<li>Item 2</li>
</ul>
Negative values for the CSS height property are invalid and will be rejected by browsers.
The CSS height property accepts only non-negative values. Valid values include auto, lengths like 100px or 10em, percentages like 50%, and viewport units like 100vh. A negative value such as height: -50px has no defined meaning for box dimensions and violates the CSS specification.
This error typically appears when height is set inline via the style attribute, and the W3C validator flags it during HTML validation. Common causes include typos, incorrect calculations in server-side templates, or JavaScript that generates a negative value and writes it into the markup.
If the intent is to hide or collapse an element, use height: 0 combined with overflow: hidden instead. If the intent is to shrink an element relative to some reference, use calc() with a positive result, such as height: calc(100% - 50px).
HTML examples
Invalid: negative height value
<divstyle="height:-100px;">
Content here
</div>
Valid: using zero height or calc()
<!-- Collapse an element -->
<divstyle="height:0;overflow: hidden;">
Hidden content
</div>
<!-- Subtract from a reference value -->
<divstyle="height:calc(100vh-100px);">
Content here
</div>
A non-standard value high is being used for the prefers-contrast media feature in a <style> block or style attribute, but the valid values are no-preference, more, less, and custom.
The prefers-contrast media feature detects whether the user has requested more or less contrast through their operating system or browser settings. Early drafts of the specification used high and low as values, and some older references still mention them. The current specification replaced these with more and less.
The W3C validator flags high because it checks CSS within HTML documents against current standards. Even though some browsers may still accept high as an alias, it is non-standard and should be replaced with more.
The mapping from old to new values:
high→morelow→less
HTML example with the issue
<style>
@media(prefers-contrast: high){
body{
background: white;
color: black;
}
}
</style>
Fixed example
<style>
@media(prefers-contrast: more){
body{
background: white;
color: black;
}
}
</style>
The left property specifies the horizontal offset of a positioned element — one that has its position set to relative, absolute, fixed, or sticky. The W3C validator checks CSS within style attributes and <style> elements, and it will flag any value it cannot recognize as a valid left value.
Common causes of this error include:
- Misspelled or non-existent units: Writing
10 px(with a space),10pixels, or20ppxinstead of10px. - Unsupported keywords: Using values like
none,center, ormiddle, which are not valid for theleftproperty. - Missing units on non-zero numbers: Writing
left: 10instead ofleft: 10px. Zero is the only number that doesn't require a unit. - Typos in keyword values: Writing
auтоorautooinstead ofauto. - CSS custom properties in inline styles: Using
var(--offset)in astyleattribute may trigger validation warnings depending on the validator's CSS level.
The valid values for the left property are:
<length>: A numeric value with a unit, such as10px,2em,3rem,1vw.<percentage>: A percentage relative to the containing block's width, such as50%.auto: Lets the browser determine the position (this is the default).- Global keywords:
inherit,initial,unset, andrevert.
Using an invalid value means the browser will ignore the declaration entirely, which can break your layout. Fixing these values ensures consistent rendering across browsers and compliance with CSS standards.
Examples
Invalid: Using an unsupported keyword
The keyword none is not a valid value for the left property.
<divstyle="position: absolute;left: none;">Positioned element</div>
Invalid: Missing unit on a non-zero number
A bare number (other than 0) is not valid without a CSS unit.
<divstyle="position: relative;left:20;">Shifted element</div>
Invalid: Misspelled unit
The unit xp does not exist in CSS.
<divstyle="position: absolute;left:15xp;">Positioned element</div>
Valid: Using a length value
<divstyle="position: absolute;left:20px;">20 pixels from the left</div>
Valid: Using a percentage
<divstyle="position: absolute;left:50%;">Offset by 50% of containing block</div>
Valid: Using the auto keyword
<divstyle="position: absolute;left: auto;">Browser-determined position</div>
Valid: Using zero without a unit
Zero does not require a unit in CSS.
<divstyle="position: absolute;left:0;">Flush with the left edge</div>
Valid: Using inherit
<divstyle="position: relative;left: inherit;">Inherits left value from parent</div>
To fix this error, identify the invalid value the validator is reporting and replace it with one of the accepted value types listed above. If you intended to reset the position, use auto or 0. If you meant to remove a previously set left value, use initial or unset rather than an unsupported keyword like none.
The mask CSS shorthand property allows you to partially or fully hide portions of an element by applying a graphical mask. It is a shorthand for several sub-properties including mask-image, mask-mode, mask-repeat, mask-position, mask-clip, mask-origin, mask-size, and mask-composite. Because it's a shorthand, each value you provide must correspond to one of these sub-properties' accepted values. The validator triggers this error when it encounters a value that doesn't fit any of them — for example, an arbitrary keyword, a misspelled function name, or an unsupported syntax.
Common causes of this error include:
- Arbitrary keywords — Using made-up names like
star-shapeorcircle-maskthat aren't valid CSS values. - Misspelled functions or keywords — Typos such as
lnear-gradient()instead oflinear-gradient(), ornoeninstead ofnone. - Browser-prefixed values without the standard value — Using
-webkit-masksyntax or values that don't align with the standardmaskproperty. - Invalid shorthand combinations — Providing sub-property values in an order or combination the shorthand doesn't accept.
- Missing
url()wrapper — Referencing an image file path directly without wrapping it in theurl()function.
This matters for standards compliance because browsers may silently ignore invalid mask values, resulting in the mask not being applied at all. Your design could look completely different than intended, and the failure may be hard to debug without validation.
Valid mask values
The mask property accepts one or more comma-separated mask layers. Each layer can include:
none— No mask is applied.url()— A reference to an SVG mask element or an image file (e.g.,url(mask.svg),url(mask.png)).- CSS image functions — Such as
linear-gradient(),radial-gradient(),conic-gradient(),image(), etc. - Geometry box keywords (for
mask-clip/mask-origin) — Such ascontent-box,padding-box,border-box,fill-box,stroke-box,view-box. - Compositing keywords (for
mask-composite) — Such asadd,subtract,intersect,exclude.
Examples
Incorrect: arbitrary keyword as a mask value
<divstyle="mask: star-shape;">
Masked Content
</div>
The value star-shape is not a recognized mask value and will be rejected by the validator.
Incorrect: missing url() function
<divstyle="mask: star.svg;">
Masked Content
</div>
A bare file path is not valid. Image references must be wrapped in the url() function.
Correct: using url() to reference a mask image
<divstyle="mask:url(star.svg);">
Masked Content
</div>
Correct: using none to explicitly disable masking
<divstyle="mask: none;">
No Mask Applied
</div>
Correct: using a gradient as a mask
<divstyle="mask:linear-gradient(to right, transparent, black);">
Fading Content
</div>
Correct: combining multiple shorthand values
<divstyle="mask:url(mask.png) no-repeat center / contain;">
Masked Content
</div>
This sets the mask image, repeat behavior, position, and size in a single shorthand declaration.
Correct: multiple mask layers
<divstyle="mask:url(shape.svg) no-repeat,linear-gradient(to bottom, black, transparent);">
Multi-layer Mask
</div>
When fixing this error, double-check your value against the CSS Masking specification on MDN. If you're using vendor-prefixed versions like -webkit-mask, also ensure the standard mask property is present with valid values for forward compatibility.
The id attribute uniquely identifies an element within a document. According to the WHATWG HTML living standard, if the id attribute is specified, its value must be non-empty and must not contain any ASCII whitespace characters. The attribute itself is optional — you don't need to include it — but when you do, it must have a valid value. Setting id="" violates this rule because the empty string is not a valid identifier.
This issue commonly occurs when code is generated dynamically (e.g., by a templating engine or JavaScript framework) and the variable intended to populate the id value resolves to an empty string. It can also happen when developers add the attribute as a placeholder and forget to fill it in.
Why this matters
- Standards compliance: An empty
idviolates the HTML specification, making your document invalid. - Accessibility: Assistive technologies like screen readers rely on
idattributes to associate<label>elements with form controls. An emptyidbreaks this association, making forms harder to use for people who depend on these tools. - JavaScript and CSS: Methods like
document.getElementById("")and selectors like#(with no identifier) will not work as expected. An emptyidcan cause subtle, hard-to-debug issues in your scripts and styles. - Browser behavior: While browsers are generally forgiving, an empty
idleads to undefined behavior. Different browsers may handle it inconsistently.
How to fix it
- Assign a meaningful value: Give the
ida descriptive, unique value that identifies the element's purpose (e.g.,id="country-select"). - Remove the attribute: If you don't need the
id, simply remove it from the element altogether. - Fix dynamic generation: If a templating engine or framework is producing the empty value, add a conditional check to either output a valid
idor omit the attribute entirely.
Examples
❌ Incorrect: empty id attribute
<labelfor="country">Country</label>
<selectid=""name="country">
<optionvalue="us">United States</option>
<optionvalue="ca">Canada</option>
</select>
This triggers the validation error because id="" is an empty string.
✅ Correct: meaningful id value
<labelfor="country">Country</label>
<selectid="country"name="country">
<optionvalue="us">United States</option>
<optionvalue="ca">Canada</option>
</select>
The id now has a valid, non-empty value, and the <label> element's for attribute correctly references it.
✅ Correct: id attribute removed entirely
<label>
Country
<selectname="country">
<optionvalue="us">United States</option>
<optionvalue="ca">Canada</option>
</select>
</label>
If you don't need the id, remove it. Here, the <label> wraps the <select> directly, so the for/id association isn't needed — the implicit label works just as well.
The aria-activedescendant attribute tells assistive technologies which child element within a composite widget — such as a combobox, listbox, or autocomplete dropdown — is currently "active" or focused. Instead of moving actual DOM focus to each option, the parent element (like an input) retains focus while aria-activedescendant points to the visually highlighted option by referencing its id. This allows screen readers to announce the active option without disrupting keyboard interaction on the input.
When aria-activedescendant is set to an empty string (""), it creates an invalid state. The HTML and ARIA specifications require that any ID reference attribute either contains a valid, non-empty ID token or is omitted altogether. An empty string is not a valid ID, so the W3C validator flags this as an error: Bad value "" for attribute "aria-activedescendant" on element "input": An ID must not be the empty string.
This problem commonly occurs in JavaScript-driven widgets where aria-activedescendant is cleared by setting it to "" when no option is highlighted — for example, when a dropdown closes or the user clears their selection. While the developer's intent is correct (indicating that nothing is active), the implementation is wrong.
Why this matters
- Accessibility: Screen readers may behave unpredictably when encountering an empty ID reference. Some may silently ignore it, while others may announce errors or fail to convey widget state correctly.
- Standards compliance: The ARIA specification explicitly requires ID reference values to be non-empty strings that match an existing element's
id. - Browser consistency: Browsers handle invalid ARIA attributes inconsistently, which can lead to different experiences across platforms and assistive technologies.
How to fix it
- Remove the attribute when no descendant is active. Use
removeAttribute('aria-activedescendant')in JavaScript instead of setting it to an empty string. - Set a valid ID when a descendant becomes active, pointing to the
idof the currently highlighted or selected option. - Never render the attribute in HTML with an empty value. If your framework or templating engine conditionally renders attributes, ensure it omits the attribute entirely rather than outputting
aria-activedescendant="".
Examples
Incorrect: empty string value
This triggers the W3C validation error because the attribute value is an empty string.
<inputtype="text"role="combobox"aria-activedescendant=""/>
Correct: attribute omitted when no option is active
When nothing is active, simply leave the attribute off.
<inputtype="text"role="combobox"aria-expanded="false"/>
Correct: valid ID reference when an option is active
When a user highlights an option, set aria-activedescendant to that option's id.
<divrole="combobox">
<input
type="text"
role="combobox"
aria-expanded="true"
aria-controls="suggestions"
aria-activedescendant="option2"/>
<ulid="suggestions"role="listbox">
<liid="option1"role="option">Apple</li>
<liid="option2"role="option"aria-selected="true">Banana</li>
<liid="option3"role="option">Cherry</li>
</ul>
</div>
Correct: managing the attribute dynamically with JavaScript
The key fix in JavaScript is using removeAttribute instead of setting the value to an empty string.
<divrole="combobox">
<input
id="search"
type="text"
role="combobox"
aria-expanded="true"
aria-controls="results"/>
<ulid="results"role="listbox">
<liid="result1"role="option">First result</li>
<liid="result2"role="option">Second result</li>
</ul>
</div>
<script>
constinput=document.getElementById('search');
functionsetActiveOption(optionId){
if(optionId){
input.setAttribute('aria-activedescendant',optionId);
}else{
// Remove the attribute instead of setting it to ""
input.removeAttribute('aria-activedescendant');
}
}
</script>
In summary, always ensure aria-activedescendant either points to a real, non-empty id or is removed from the element. Never set it to an empty string.
The <textarea> element represents a multi-line plain-text editing control, commonly used for comments, feedback forms, and other free-form text input. The rows attribute specifies the number of visible text lines the textarea should display. According to the HTML specification, when the rows attribute is present, its value must be a valid positive integer — meaning a string of one or more digits representing a number greater than zero (e.g., 1, 5, 20). An empty string ("") does not meet this requirement.
This issue typically occurs when a template engine, CMS, or JavaScript framework dynamically sets the rows attribute but outputs an empty value instead of a number, or when a developer adds the attribute as a placeholder intending to fill it in later.
Why this matters
- Standards compliance: The HTML specification explicitly requires
rowsto be a positive integer when present. An empty string violates this rule. - Unpredictable rendering: Browsers fall back to a default value (typically
2) when they encounter an invalidrowsvalue, but this behavior isn't guaranteed to be consistent across all browsers and versions. - Maintainability: Invalid attributes can mask bugs in dynamic code that was supposed to provide a real value.
How to fix it
You have two options:
- Set a valid positive integer: Replace the empty string with a number like
4,5, or whatever suits your design. - Remove the attribute: If you don't need to control the number of visible rows (or prefer to handle sizing with CSS), simply omit the
rowsattribute. The browser will use its default.
If the value is generated dynamically, ensure your code has a fallback so it never outputs an empty string. You can also control the textarea's height using CSS (height or min-height) instead of relying on the rows attribute.
Examples
❌ Invalid: empty string for rows
<textareaname="comments"rows=""cols="25">
</textarea>
This triggers the error because "" is not a valid positive integer.
✅ Fixed: providing a valid positive integer
<textareaname="comments"rows="5"cols="25">
</textarea>
Setting rows="5" tells the browser to display five visible lines of text.
✅ Fixed: removing the attribute entirely
<textareaname="comments"cols="25">
</textarea>
When rows is omitted, the browser uses its default (typically 2 rows). This is perfectly valid.
✅ Alternative: using CSS for sizing
<textareaname="comments"style="height:10em;width:25ch;">
</textarea>
If you need precise control over the textarea's dimensions, CSS properties like height, min-height, and width give you more flexibility than the rows and cols attributes. In this case, you can safely leave both attributes off.
The HTML living standard defines that scripts with type="module" are always fetched in parallel and evaluated after the document has been parsed, which is the same behavior that the defer attribute provides for classic scripts. Because this deferred execution is an inherent characteristic of module scripts, the spec explicitly forbids combining the two. Including both doesn't change how the browser handles the script, but it signals a misunderstanding of how modules work and produces invalid HTML.
This validation error commonly arises when developers migrate classic scripts to ES modules. A classic script like <script defer src="app.js"></script> relies on the defer attribute to avoid blocking the parser. When converting to a module by adding type="module", it's natural to leave defer in place — but it's no longer needed or allowed.
It's worth noting that the async attribute is valid on module scripts and does change their behavior. While defer is redundant because modules are already deferred, async overrides that default and causes the module to execute as soon as it and its dependencies have finished loading, rather than waiting for HTML parsing to complete.
How to Fix
Remove the defer attribute from any <script> element that has type="module". No other changes are needed — the loading and execution behavior will remain identical.
If you intentionally want the script to run as soon as possible (before parsing completes), use async instead of defer. But if you want the standard deferred behavior, simply omit both attributes and let the module default take effect.
Examples
❌ Incorrect: defer combined with type="module"
<scripttype="module"defersrc="app.js"></script>
The defer attribute is redundant here and causes a validation error.
✅ Correct: module script without defer
<scripttype="module"src="app.js"></script>
Module scripts are deferred automatically, so this behaves exactly the same as the incorrect example above but is valid HTML.
✅ Correct: using async with a module (when needed)
<scripttype="module"asyncsrc="analytics.js"></script>
Unlike defer, the async attribute is permitted on module scripts. It causes the module to execute as soon as it's ready, without waiting for HTML parsing to finish.
✅ Correct: classic script with defer
<scriptdefersrc="app.js"></script>
For classic (non-module) scripts, the defer attribute is valid and necessary if you want deferred execution.
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