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.
Changing the character encoding declaration too late in the document prevents the browser from processing it correctly. The <meta charset> declaration must appear within the first 1024 bytes of the HTML document, and specifically before any non-ASCII content.
When a browser parses an HTML document, it reads the bytes as a stream. If it encounters a <meta charset> tag after it has already started interpreting content, it would need to go back and re-parse everything from the beginning — this is "non-streamable behavior." To avoid this, the HTML specification requires that the charset declaration appear very early in the document.
The most common causes of this error are:
- Placing
<meta charset>after other large<meta>tags, long<title>content, or<script>blocks in the<head>. - Placing
<meta charset>after content that pushes it beyond the 1024-byte boundary. - Including it in the
<body>instead of the<head>.
The fix is simple: make <meta charset="utf-8"> the very first element inside <head>, before any other elements.
Incorrect Example
<!DOCTYPE html>
<html lang="en">
<head>
<title>A very long title that takes up many bytes and pushes the charset declaration further down in the document stream...</title>
<meta name="description" content="A very long description with lots of text that consumes bytes before the charset is declared...">
<meta charset="utf-8">
</head>
<body>
<p>Hello world</p>
</body>
</html>
Corrected Example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>A very long title that takes up many bytes...</title>
<meta name="description" content="A very long description with lots of text...">
</head>
<body>
<p>Hello world</p>
</body>
</html>
Always keep <meta charset="utf-8"> as the first child of <head>. This ensures the browser knows the encoding before it processes any other content.
What Are Control Characters?
Control characters occupy code points U+0000 through U+001F and U+007F through U+009F in Unicode. They were originally designed for controlling hardware devices (e.g., U+0002 is "Start of Text," U+0007 is "Bell," U+001B is "Escape"). These characters have no visual representation and carry no semantic meaning in a web document.
The HTML specification explicitly forbids character references that resolve to most control characters. Even though the syntax  is a structurally valid character reference, the character it points to is not a permissible content character. The W3C validator raises this error to flag references like �, , , , and others that fall within the control character ranges.
Why This Is a Problem
- Standards compliance: The WHATWG HTML Living Standard defines a specific set of "noncharacter" and "control character" code points that must not be referenced. Using them produces a parse error.
- Unpredictable rendering: Browsers handle illegal control characters inconsistently. Some may silently discard them, others may render a replacement character (�), and others may exhibit unexpected behavior.
- Accessibility: Screen readers and other assistive technologies may choke on or misinterpret control characters, degrading the experience for users who rely on these tools.
- Data integrity: Control characters in your markup often indicate a copy-paste error, a corrupted data source, or a templating bug that inserts raw binary data into HTML output.
How to Fix It
- Identify the offending reference — look for character references like
,,�,, or similar that point to control character code points. - Determine intent — figure out what character or content was actually intended. Often, a control character reference is the result of a bug in a data pipeline or template engine.
- Remove or replace — either delete the reference entirely or replace it with the correct printable character or HTML entity.
Examples
Incorrect: Control character reference
This markup contains , which expands to the control character U+0002 (Start of Text) and triggers the validation error:
<p>Some text  more text</p>
Incorrect: Hexadecimal form of a control character
The same problem occurs with the hexadecimal syntax:
<p>Data: </p>
Correct: Remove the control character reference
If the control character was unintentional, simply remove it:
<p>Some text more text</p>
Correct: Use a valid character reference instead
If you intended to display a special character, use the correct printable code point or named entity. For example, to display a bullet (•), copyright sign (©), or ampersand (&):
<p>Item • Details</p>
<p>Copyright © 2024</p>
<p>Tom & Jerry</p>
Correct: Full document without control characters
<!DOCTYPE html>
<html lang="en">
<head>
<title>Example Page</title>
</head>
<body>
<p>This paragraph uses only valid character references: & < > ©</p>
</body>
</html>
Common Control Character Code Points to Avoid
| Reference | Code Point | Name |
|---|---|---|
� | U+0000 | Null |
 | U+0001 | Start of Heading |
 | U+0002 | Start of Text |
 | U+0007 | Bell |
 | U+0008 | Backspace |
 | U+000B | Vertical Tab |
 | U+000C | Form Feed |
 | U+007F | Delete |
If your content is generated dynamically (from a database, API, or user input), sanitize the data before inserting it into HTML to strip out control characters. Most server-side languages and templating engines provide utilities for this purpose.
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)
<a href="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
<a href="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 &.
When you use the W3C Markup Validation Service by submitting a URL (rather than uploading a file or pasting code directly), the validator attempts to fetch the page from your server over the internet. If the server doesn't respond within a set period, the connection times out and the validator reports this error instead of any HTML validation results.
This issue is entirely network- or server-related and has nothing to do with the quality of your HTML markup. However, it prevents you from validating your code, so it's worth resolving or working around.
Common Causes
There are several reasons the validator may fail to connect:
- Server is offline or unresponsive. The web server hosting your site may be down, overloaded, or restarting.
- Firewall or security rules blocking the validator. Some server configurations, Web Application Firewalls (WAFs), or hosting providers block automated requests. The W3C Validator identifies itself via its
User-Agentheader, and some security tools may reject it. - The URL is not publicly accessible. If your site is on
localhost, behind a VPN, on an intranet, or restricted by IP allowlisting, the validator cannot reach it. - DNS issues. The domain name may not resolve correctly from the validator's network, even if it works from your machine.
- SSL/TLS misconfiguration. If the site uses HTTPS but has an expired certificate, a self-signed certificate, or an incomplete certificate chain, the connection may fail or be refused.
- Slow server response. If your page takes a very long time to generate (e.g., a complex database query), the validator may time out before receiving a response.
- Cloudflare or CDN challenge pages. Services like Cloudflare may present a bot-detection challenge or CAPTCHA to the validator, preventing it from fetching the actual page.
How to Fix It
1. Verify your site is publicly reachable
Test that your URL is accessible from outside your local network. You can use tools like curl from a remote server or an online service like "Down For Everyone Or Just Me."
curl -I https://example.com
If this returns an HTTP status code like 200 OK, the server is responding.
2. Check your firewall and security rules
Make sure your server or hosting provider isn't blocking the W3C Validator's requests. The validator's User-Agent string typically contains W3C_Validator. If you use a WAF or bot-protection service, add an exception for the validator.
3. Fix SSL/TLS issues
If your site uses HTTPS, verify your certificate is valid and the chain is complete. You can test this with tools like SSL Labs.
4. Use an alternative validation method
If you can't make your site publicly accessible to the validator (e.g., it's a staging server or a local development environment), you can bypass the network requirement entirely:
- Direct input: Copy your page's HTML source and paste it into the validator's "Validate by Direct Input" tab at validator.w3.org.
- File upload: Save the HTML file locally and use the "Validate by File Upload" tab.
- View source, then paste: In your browser, view the page source (
Ctrl+UorCmd+U), copy the full HTML, and paste it into the validator.
5. Reduce server response time
If your server is online but slow, optimize the page so it responds faster. The validator expects a response within a reasonable timeout window. Consider caching, reducing database queries, or simplifying server-side processing for the page you're trying to validate.
Examples
Validating a local development site (will fail)
Submitting a URL like this to the W3C Validator will time out because the validator cannot access your local machine:
http://localhost:3000/index.html
http://192.168.1.50/mysite/
http://my-dev-machine.local/page.html
Workaround: Validate by direct input
Instead, copy your HTML and paste it directly. For example, if your page contains:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>My Page</title>
</head>
<body>
<h1>Hello, world!</h1>
<p>This is my page.</p>
</body>
</html>
Paste this into the "Validate by Direct Input" field on the W3C Validator. This completely avoids the network connection and lets you validate your markup regardless of server accessibility.
The lang attribute on the <html> element sets the default language for all text content within the page. Without it, assistive technologies like screen readers have to guess which language the content is in, which can lead to garbled or incorrectly pronounced text. For example, a French screen reader attempting to read English text — or vice versa — produces a poor experience for users who rely on these tools.
Beyond accessibility, the lang attribute matters for several other reasons:
- Search engines use it to serve the correct language version of your page in search results.
- Browsers rely on it to choose appropriate fonts, hyphenation rules, and quotation mark styles.
- Translation tools use it to detect the source language of the page.
- CSS selectors like
:lang()depend on it to apply language-specific styling.
The value of the lang attribute must be a valid BCP 47 language tag. Common examples include en (English), fr (French), es (Spanish), de (German), zh (Chinese), ja (Japanese), and ar (Arabic). You can also be more specific with region subtags, such as en-US for American English or pt-BR for Brazilian Portuguese.
If your page contains sections in a different language than the primary one, you can use the lang attribute on individual elements to override the document-level language for that section.
Examples
Missing lang attribute (triggers the warning)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>My Page</title>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
Fixed with lang attribute
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>My Page</title>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
Using a region subtag for specificity
<!DOCTYPE html>
<html lang="en-GB">
<head>
<meta charset="utf-8">
<title>My Page</title>
</head>
<body>
<p>Colour is spelt differently here.</p>
</body>
</html>
Overriding the language for a specific section
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Multilingual Page</title>
</head>
<body>
<p>This paragraph is in English.</p>
<p lang="fr">Ce paragraphe est en français.</p>
</body>
</html>
In this last example, the document language is English, but the second paragraph is marked as French. A screen reader will switch to French pronunciation rules for that paragraph, then revert to English for the rest of the page.
When you set user-scalable=no in your viewport meta tag, the browser completely disables pinch-to-zoom and other scaling gestures on mobile devices. Similarly, setting maximum-scale=1 (or any low value) caps how far a user can zoom in, effectively locking them out of enlarging content. While developers sometimes use these values to create an "app-like" experience or prevent layout issues during zoom, they directly violate accessibility best practices.
Why this is a problem
Accessibility
The Web Content Accessibility Guidelines (WCAG) Success Criterion 1.4.4 (Resize Text) requires that text can be resized up to 200% without loss of content or functionality. Preventing zoom makes it impossible for users with low vision, cognitive disabilities, or motor impairments to interact comfortably with your page. Many users depend on pinch-to-zoom as their primary way to read content on mobile devices.
Standards compliance
The W3C HTML Validator flags this as a warning because it conflicts with established accessibility standards. While it won't cause your page to fail validation outright, it signals a practice that harms usability. Modern browsers and operating systems have also started to override restrictive viewport settings in some cases — for example, iOS Safari ignores user-scalable=no by default — which means the restriction may not even work as intended while still triggering warnings.
User experience
Even for users without disabilities, preventing zoom can be frustrating. Small text, dense layouts, or content that doesn't quite fit a screen size can all benefit from the user being able to zoom in. Restricting this capability removes a fundamental browser feature that users expect.
How to fix it
- Remove
user-scalable=nofrom your viewport meta tag. If present, either delete it or set it toyes. - Remove or increase
maximum-scale. If you need to set it, use a value of5or higher. Ideally, remove it entirely and let the browser handle zoom limits. - Remove
minimum-scaleif it's set to1, as this can also restrict zoom behavior on some browsers when combined with other values. - Test your layout at various zoom levels to ensure content reflows properly and remains usable.
Examples
❌ Viewport that prevents zooming
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
This completely disables user zoom on supporting browsers.
❌ Viewport with restrictive maximum-scale
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0">
This caps zoom at 100%, effectively preventing any meaningful zoom.
❌ Both restrictions combined
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
This is the most restrictive combination and is commonly seen in mobile-first frameworks and templates.
✅ Accessible viewport (recommended)
<meta name="viewport" content="width=device-width, initial-scale=1">
This sets a responsive viewport without restricting zoom at all. The browser's default zoom behavior is preserved, and users can scale freely.
✅ Accessible viewport with a generous maximum-scale
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=5">
If you have a specific reason to set maximum-scale, use a value of 5 or higher. This still allows substantial zoom while giving you some control over extreme zoom levels.
✅ Full document example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Accessible Page</title>
</head>
<body>
<h1>Welcome</h1>
<p>This page allows users to zoom freely.</p>
</body>
</html>
If your layout breaks when users zoom in, the solution is to fix the CSS — using relative units like em, rem, or percentages, and responsive design techniques — rather than disabling zoom. A well-built responsive layout should handle zoom gracefully without needing to restrict it.
The HTML heading elements <h1> through <h6> define a document's heading hierarchy. The <h1> element represents the highest-level heading, and each subsequent level (<h2>, <h3>, etc.) represents a deeper subsection. This hierarchy is critical for both accessibility and document structure.
The HTML5 specification once introduced a "document outline algorithm" that would have allowed multiple <h1> elements to be automatically scoped by their parent sectioning elements (<section>, <article>, <nav>, <aside>). Under this model, an <h1> inside a nested <section> would be treated as a lower-level heading. However, no browser or assistive technology ever implemented this algorithm. The outline algorithm was eventually removed from the WHATWG HTML specification. In practice, screen readers and other tools treat every <h1> on a page as a top-level heading, regardless of nesting.
This matters for several reasons:
- Accessibility: Screen reader users frequently navigate by headings to get an overview of a page's content. When multiple
<h1>elements exist, the heading list becomes flat and unclear, making it difficult to understand the page's structure and find specific content. - SEO: Search engines use heading hierarchy to understand page structure and content importance. Multiple
<h1>elements can dilute the semantic signal of your primary page topic. - Standards compliance: While using multiple
<h1>elements is not a validation error, the W3C validator raises this as a warning because it is widely considered a best practice to reserve<h1>for the single, top-level page heading.
To fix this warning, follow these guidelines:
- Use exactly one
<h1>per page to describe the main topic or title. - Use
<h2>for major sections beneath it,<h3>for subsections within those, and so on. - Don't skip heading levels (e.g., jumping from
<h1>to<h3>without an<h2>).
Examples
Incorrect: Multiple <h1> elements
This example uses <h1> inside each sectioning element, which triggers the warning. Screen readers will present all three headings at the same level, losing the intended hierarchy.
<h1>My Blog</h1>
<section>
<h1>Latest Posts</h1>
<article>
<h1>How to Write Accessible HTML</h1>
<p>Writing semantic HTML is important for accessibility.</p>
</article>
<article>
<h1>Understanding CSS Grid</h1>
<p>CSS Grid makes complex layouts straightforward.</p>
</article>
</section>
Correct: Proper heading hierarchy
Use a single <h1> for the page title and nest subsequent headings using the appropriate levels.
<h1>My Blog</h1>
<section>
<h2>Latest Posts</h2>
<article>
<h3>How to Write Accessible HTML</h3>
<p>Writing semantic HTML is important for accessibility.</p>
</article>
<article>
<h3>Understanding CSS Grid</h3>
<p>CSS Grid makes complex layouts straightforward.</p>
</article>
</section>
Incorrect: <h1> nested inside a section without a parent heading
Even a single <h1> nested deeply inside sectioning content can trigger this warning if the structure suggests it is not the page's primary heading.
<section class="about">
<article>
<h1>Article heading</h1>
<p>Lorem ipsum dolor sit amet.</p>
</article>
</section>
Correct: Section with its own heading and properly ranked article heading
<section class="about">
<h1>About</h1>
<article>
<h2>Article heading</h2>
<p>Lorem ipsum dolor sit amet.</p>
</article>
</section>
Correct: Full page structure with clear heading hierarchy
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Company Homepage</title>
</head>
<body>
<header>
<h1>Acme Corporation</h1>
</header>
<main>
<section>
<h2>Our Services</h2>
<h3>Web Development</h3>
<p>We build modern, accessible websites.</p>
<h3>Design</h3>
<p>Our design team creates beautiful interfaces.</p>
</section>
<section>
<h2>About Us</h2>
<p>We have been in business since 2005.</p>
</section>
</main>
</body>
</html>
In this structure, screen readers will present a clear, navigable outline: one top-level heading followed by properly nested subheadings that reflect the logical organization of the content.
Multiple h1 elements on a page can confuse screen readers and other assistive tools, which treat every h1 as the top-level heading.
HTML headings (h1 through h6) form an outline of your document. The h1 element represents the highest-level heading, and most accessibility guidelines recommend using only one h1 per page. When screen readers encounter multiple h1 elements, they may present them all as equally important top-level sections, making it harder for users to understand the page structure.
Instead of using multiple h1 elements, use a proper heading hierarchy. Start with a single h1 for the main topic of the page, then use h2 for major sections, h3 for subsections, and so on. This creates a clear, navigable document outline.
The W3C warning also mentions a headingoffset attribute, which is a proposed feature for <section> elements that would allow automatic heading level adjustment. However, this attribute is not yet implemented in any browser, so you should not rely on it.
Example with the issue
<body>
<h1>My Website</h1>
<section>
<h1>About Us</h1>
<p>Some content here.</p>
</section>
<section>
<h1>Contact</h1>
<p>More content here.</p>
</section>
</body>
Example with proper heading hierarchy
<body>
<h1>My Website</h1>
<section>
<h2>About Us</h2>
<p>Some content here.</p>
</section>
<section>
<h2>Contact</h2>
<p>More content here.</p>
</section>
</body>
Keep one h1 per page and nest subsequent headings using h2 through h6 to reflect the logical structure of your content. This approach is well-supported across all browsers and assistive technologies today.
Content Security Policy (CSP) is a security mechanism that lets you control which resources a browser is allowed to load for your page. When defined via a <meta http-equiv="Content-Security-Policy"> tag, the validator checks whether the content attribute contains a well-formed policy. If the policy string contains unrecognized directives, malformed source expressions, or syntax errors, the validator reports "Bad content security policy."
Common causes of this error include:
- Misspelled directive names — e.g.,
script-scrinstead ofscript-src. - Invalid source values — e.g., using
selfwithout single quotes (it must be'self'). - Using directives not allowed in
<meta>tags — theframe-ancestors,report-uri, andsandboxdirectives are not supported when CSP is delivered via a<meta>element. - Incorrect separators — directives are separated by semicolons (
;), not commas or pipes. - Missing or extra quotes — keywords like
'none','self','unsafe-inline', and'unsafe-eval'must be wrapped in single quotes. Conversely, hostnames and URLs must not be quoted.
This matters because a malformed CSP may be silently ignored by browsers, leaving your site without the intended protection against cross-site scripting (XSS) and data injection attacks. Even a small typo can cause an entire directive to be skipped, creating a security gap you might not notice.
How to fix it
- Check directive names against the CSP specification. Valid fetch directives include
default-src,script-src,style-src,img-src,font-src,connect-src,media-src,object-src,child-src,worker-src, and others. - Wrap keyword values in single quotes:
'self','none','unsafe-inline','unsafe-eval', and nonce/hash sources like'nonce-abc123'. - Separate directives with semicolons. Multiple source values within a single directive are separated by spaces.
- Avoid directives that are invalid in
<meta>tags. If you needframe-ancestorsorreport-uri, deliver CSP via an HTTP header instead. - Don't include the header name inside the
contentattribute. Thecontentvalue should contain only the policy itself.
Examples
❌ Misspelled directive and unquoted keyword
<meta http-equiv="Content-Security-Policy"
content="default-src self; script-scr https://example.com">
Here, self is missing its required single quotes, and script-scr is a typo for script-src.
✅ Corrected directive name and properly quoted keyword
<meta http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src https://example.com">
❌ Using a directive not allowed in a <meta> tag
<meta http-equiv="Content-Security-Policy"
content="default-src 'self'; frame-ancestors 'none'">
The frame-ancestors directive is ignored in <meta> elements and may trigger a validation warning.
✅ Removing the unsupported directive from the <meta> tag
<meta http-equiv="Content-Security-Policy"
content="default-src 'self'">
Deliver frame-ancestors via an HTTP response header on your server instead.
❌ Using commas instead of semicolons between directives
<meta http-equiv="Content-Security-Policy"
content="default-src 'self', script-src 'none', style-src 'self'">
✅ Using semicolons to separate directives
<meta http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'none'; style-src 'self'">
❌ Quoting a hostname (hostnames must not be in quotes)
<meta http-equiv="Content-Security-Policy"
content="default-src 'self'; img-src 'https://images.example.com'">
✅ Hostname without quotes
<meta http-equiv="Content-Security-Policy"
content="default-src 'self'; img-src https://images.example.com">
When in doubt, use an online CSP evaluator to validate your policy string before adding it to your HTML. This ensures both syntactic correctness and that the policy actually enforces what you intend.
The align-items property controls how flex or grid items are aligned along the cross axis of their container. While many CSS properties accept auto as a value, align-items is not one of them. The CSS specification defines a specific set of accepted values, and using auto will cause the declaration to be ignored by browsers, potentially breaking your intended layout.
This mistake often stems from confusion with the related property align-self, which does accept auto as its default value. When align-self is set to auto, it defers to the parent container's align-items value. However, align-items itself has no such delegation mechanism — it is the property that sets the default alignment for all items in the container.
The valid values for align-items include:
normal— behaves asstretchin flex containers and has context-dependent behavior in other layout modes.stretch— items are stretched to fill the container along the cross axis (the default behavior in flexbox).center— items are centered along the cross axis.flex-start/start— items are aligned to the start of the cross axis.flex-end/end— items are aligned to the end of the cross axis.baseline/first baseline/last baseline— items are aligned based on their text baselines.self-start/self-end— items are aligned based on their own writing mode.
If you intended the default behavior, use stretch (for flexbox) or normal. If you were trying to reset the property, use initial, unset, or revert instead of auto.
Examples
Incorrect: using auto as a value
<div style="display: flex; align-items: auto;">
<p>Item one</p>
<p>Item two</p>
</div>
This triggers the validation error because auto is not a recognized value for align-items.
Fixed: using stretch for default flexbox behavior
<div style="display: flex; align-items: stretch;">
<p>Item one</p>
<p>Item two</p>
</div>
Fixed: using center to center items
<div style="display: flex; align-items: center;">
<p>Item one</p>
<p>Item two</p>
</div>
Fixed: using flex-start to align items to the top
<div style="display: flex; align-items: flex-start;">
<p>Item one</p>
<p>Item two</p>
</div>
Correct use of auto with align-self
If your intention was to let a specific child item defer to its parent's alignment, use align-self: auto on the child element instead:
<div style="display: flex; align-items: center;">
<p>Centered item</p>
<p style="align-self: auto;">Also centered (defers to parent)</p>
<p style="align-self: flex-end;">Aligned to the end</p>
</div>
Here, align-self: auto is valid on individual items and tells them to inherit the align-items value from the container.
left is not a valid value for the align-items CSS property.
The align-items property controls how flex or grid items are aligned along the cross axis of their container. Its valid values include stretch, flex-start, flex-end, center, baseline, start, end, self-start, and self-end.
The value left is not recognized because align-items works on the cross axis (typically vertical), not the inline/horizontal axis. If you want to align items to the start, use flex-start or start instead.
If you're actually trying to align content horizontally to the left, you likely want the justify-content property (which controls the main axis) or text-align: left on the container.
How to Fix
Incorrect:
<div style="display: flex; align-items: left;">
<p>Hello</p>
</div>
Fixed — aligning items to the start of the cross axis:
<div style="display: flex; align-items: flex-start;">
<p>Hello</p>
</div>
Fixed — aligning items horizontally to the left (main axis):
<div style="display: flex; justify-content: flex-start;">
<p>Hello</p>
</div>
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
<div style="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
<div style="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.
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
<div style="animation: none;">No animation here</div>
Using the longhand property to avoid the warning
<div style="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.
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
<div style="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
<div style="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
<div style="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
<div style="aspect-ratio: 16 / 9; width: 100%;"></div>
Correct: single number (height defaults to 1)
<div style="aspect-ratio: 2; width: 100%;"></div>
This is equivalent to aspect-ratio: 2 / 1.
Correct: square ratio
<div style="aspect-ratio: 1 / 1; width: 100%;"></div>
Correct: using the auto keyword
<img src="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
<img src="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
<div style="aspect-ratio: inherit; width: 100%;"></div>
Global values like inherit, initial, unset, revert, and revert-layer are also valid.
The background-blend-mode property controls how an element's background layers — including background images and background colors — blend with each other. Each value must be a valid blend mode keyword as defined in the CSS Compositing and Blending specification. The W3C validator flags this error when it encounters a value that doesn't match any recognized keyword, which can happen due to typos, made-up values, or confusion with similar properties like mix-blend-mode.
While browsers typically ignore unrecognized CSS values and fall back to the default (normal), relying on this behavior is risky. It means the blending effect you intended simply won't appear, and the silent failure can be hard to debug. Fixing validation errors ensures your styles work as intended across all browsers.
The complete list of valid values for background-blend-mode is:
normal(default)multiplyscreenoverlaydarkenlightencolor-dodgecolor-burnhard-lightsoft-lightdifferenceexclusionhuesaturationcolorluminosity
You can also specify multiple comma-separated values when an element has multiple background layers. Each value corresponds to a background layer in the same order.
Examples
Invalid values
These examples will trigger the validation error:
/* Typo: "multipley" is not a valid keyword */
.hero {
background-blend-mode: multipley;
}
/* "blend" is not a recognized value */
.banner {
background-blend-mode: blend;
}
/* Numeric values are not accepted */
.card {
background-blend-mode: 50%;
}
Corrected values
/* Fixed: correct spelling */
.hero {
background-blend-mode: multiply;
}
/* Fixed: use a valid blend mode keyword */
.banner {
background-blend-mode: overlay;
}
/* Fixed: use a keyword instead of a numeric value */
.card {
background-blend-mode: soft-light;
}
Multiple background layers
When you have multiple background images, provide a comma-separated list of valid blend modes:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Background Blend Mode Example</title>
<style>
.blended {
width: 300px;
height: 200px;
background-color: teal;
background-image: url("pattern.png"), url("photo.jpg");
background-blend-mode: screen, multiply;
}
</style>
</head>
<body>
<div class="blended">Blended background layers</div>
</body>
</html>
In this example, screen applies to the first background image layer and multiply applies to the second. Both are valid keywords, so no validation error is produced.
When you write a hex color in CSS, the # symbol must be followed by exactly 3, 4, 6, or 8 hexadecimal digits (characters 0–9 and a–f). Writing background-color: #; or background-color: #; means the CSS parser encounters the statement-ending semicolon immediately after #, with no color data. The parser cannot interpret this as a valid token, so it throws a lexical error.
This commonly happens when:
- A color value is accidentally deleted or left as a placeholder during development.
- A template engine or CMS outputs an empty variable where a color value was expected (e.g.,
background-color: #{{ color }};wherecoloris empty). - A hex value is truncated, such as
#for#zz, containing an invalid number of digits or non-hex characters.
While most browsers will silently ignore the invalid declaration and fall back to the inherited or default background color, this creates unpredictable behavior. The element may render differently than intended, and the invalid CSS clutters your codebase. Fixing it ensures consistent rendering and standards compliance.
How to fix it
- Find the error location. The validator message includes the line and column number — go to that exact spot in your HTML or CSS file.
- Look at the
background-colorvalue. You'll likely see#followed immediately by;, or a#with an incomplete or invalid hex string. - Provide a valid color value. Replace the broken value with a proper hex code, a color keyword, or a functional notation like
rgb()orhsl().
If the color value comes from a dynamic source (like a CMS or JavaScript variable), add a fallback so an empty value doesn't produce invalid CSS.
Examples
❌ Incomplete hex value (triggers the error)
<div style="background-color: #;">
Hello
</div>
The # has no hex digits before the semicolon, causing the lexical error.
✅ Fixed with a valid hex color
<div style="background-color: #ffffff;">
Hello
</div>
❌ Truncated or invalid hex digits
<div style="background-color: #g3;">
Hello
</div>
The character g is not a valid hexadecimal digit, and two digits is not a valid hex color length.
✅ Fixed with a proper 3-digit shorthand hex color
<div style="background-color: #f0f;">
Hello
</div>
✅ Alternative valid color formats
Any of these are valid replacements for a broken hex value:
/* 6-digit hex */
background-color: #1a2b3c;
/* 3-digit shorthand hex */
background-color: #abc;
/* 8-digit hex with alpha */
background-color: #1a2b3cff;
/* Named color keyword */
background-color: white;
/* RGB functional notation */
background-color: rgb(255, 255, 255);
/* RGBA with transparency */
background-color: rgba(0, 0, 0, 0.5);
/* HSL functional notation */
background-color: hsl(210, 50%, 60%);
/* HSLA with transparency */
background-color: hsla(210, 50%, 60%, 0.8);
✅ Defensive approach for dynamic values
If a CMS or templating system inserts the color, consider providing a fallback so an empty value doesn't break your CSS:
<div style="background-color: #f0f0f0;">
Content with a safe default background
</div>
In your template logic, ensure empty color values either output a sensible default or omit the style attribute entirely rather than producing background-color: #;.
The background-color property accepts a specific set of color value types defined in the CSS Color specification. When you provide something that doesn't match any of these types — like a plain number, a misspelled keyword, or a malformed hex code — the validator flags it as an invalid value.
Common mistakes that trigger this error include:
- Bare numbers like
0or255— numbers alone aren't colors, even if you intended black or white. - Misspelled color keywords like
grreninstead ofgreen, ortrasparentinstead oftransparent. - Malformed hex codes like
#GGG,#12345, or missing the#prefix entirely. - Incorrect function syntax like
rgb(255 0 0 0.5)when mixing legacy comma syntax with modern space syntax improperly, or usingrgbawith only three arguments. - Invalid units or strings like
background-color: 10pxorbackground-color: "red"(color values should not be quoted).
While browsers are generally forgiving and will simply ignore an invalid background-color declaration, this means your intended styling silently fails. The element falls back to its inherited or default background, which can cause visual bugs, poor contrast, or accessibility issues that are hard to track down. Validating your CSS catches these problems early.
Valid color formats
The background-color property accepts these value types:
- Named keywords:
red,blue,transparent,currentcolor, etc. - Hex notation:
#rgb,#rrggbb,#rgba,#rrggbbaa - RGB/RGBA:
rgb(255, 0, 0)orrgb(255 0 0 / 0.5) - HSL/HSLA:
hsl(120, 100%, 50%)orhsl(120 100% 50% / 0.5) - The keyword
inherit,initial,unset, orrevert
Examples
Invalid: bare number as a color
A plain number like 0 is not a valid color value, even though black could be represented as all zeros in RGB.
<style>
.banner {
background-color: 0;
}
</style>
Invalid: misspelled keyword
<style>
.banner {
background-color: trasparent;
}
</style>
Invalid: quoted string
Color values must not be wrapped in quotes.
<style>
.banner {
background-color: "red";
}
</style>
Invalid: malformed hex code
Hex codes must be 3, 4, 6, or 8 characters after the #.
<style>
.banner {
background-color: #12345;
}
</style>
Fixed: using a named color keyword
<style>
.banner {
background-color: black;
}
</style>
Fixed: using a hex color
<style>
.banner {
background-color: #000000;
}
</style>
Fixed: using rgb() notation
<style>
.banner {
background-color: rgb(0, 0, 0);
}
</style>
Fixed: using rgba() for semi-transparency
<style>
.banner {
background-color: rgba(0, 0, 0, 0.5);
}
</style>
Fixed: using hsl() notation
<style>
.banner {
background-color: hsl(210, 50%, 40%);
}
</style>
Fixed: using transparent
<style>
.banner {
background-color: transparent;
}
</style>
The background CSS property accepts a variety of value types: named colors (red, blue), hexadecimal codes (#fff, #ff0000), color functions (rgb(), hsl(), rgba()), gradient functions (linear-gradient(), radial-gradient()), image URLs, and CSS keywords like none, transparent, or inherit. The word from is not among these valid values.
Why this happens
This error most commonly appears in one of these scenarios:
Legacy WebKit gradient syntax. Older versions of Safari and Chrome used a proprietary syntax:
-webkit-gradient(linear, left top, right top, from(#fff), to(#000)). Thefrom()andto()functions are part of this deprecated, non-standard format. If this syntax is used without the-webkit-prefix—or if the validator encounters it—the wordfromgets flagged as an invalid color value.Incorrectly written gradient shorthand. Some developers unfamiliar with the CSS gradient specification write something resembling natural language, like
background: from #fff to #000, which has no meaning in CSS.CSS
fromkeyword in relative color syntax. CSS Color Level 5 introduces relative color syntax using thefromkeyword (e.g.,rgb(from red r g b / 50%)). This is a newer feature that may not yet be recognized by the W3C CSS validator, which can lag behind the latest specifications. If you're using this syntax intentionally, the error may be a false positive from the validator, but be aware that browser support may still be limited.
Why it matters
Invalid CSS values are silently ignored by browsers, meaning your intended background styling won't be applied. The element will fall back to its default or inherited background, which can result in broken layouts, missing visual cues, or poor contrast that harms readability and accessibility. Using standard, valid CSS ensures consistent rendering across all browsers.
How to fix it
- Replace legacy
-webkit-gradient()syntax with the standardlinear-gradient()orradial-gradient()functions. - Use valid color formats for solid backgrounds: hex codes, named colors, or color functions.
- If using relative color syntax (
fromkeyword in CSS Color Level 5), understand that the validator may not yet support it. Consider adding a fallback value for broader compatibility.
Examples
Incorrect: legacy WebKit gradient syntax
The from() and to() functions in -webkit-gradient() are non-standard and will trigger this error if used as a background value:
<style>
.banner {
/* Non-standard syntax; "from" is not a valid CSS value */
background: -webkit-gradient(linear, left top, right top, from(#fff), to(#000));
}
</style>
<div class="banner">Legacy gradient</div>
Incorrect: made-up gradient shorthand
Writing gradient-like syntax without a proper CSS function is invalid:
<style>
.banner {
/* "from" and "to" are not valid CSS keywords here */
background: from #fff to #000;
}
</style>
<div class="banner">Invalid gradient</div>
Correct: standard linear gradient
Use linear-gradient() with a direction and comma-separated color stops:
<style>
.banner {
background: linear-gradient(to right, #fff, #000);
}
</style>
<div class="banner">Standard gradient</div>
Correct: solid color background
For a simple solid color, use any valid CSS color value:
<style>
.banner {
background: #fff;
}
</style>
<div class="banner">White background</div>
Correct: gradient with a fallback for older browsers
When using gradients, it's good practice to provide a solid color fallback:
<style>
.banner {
background: #fff;
background: linear-gradient(to bottom, #ffffff, #cccccc);
}
</style>
<div class="banner">Gradient with fallback</div>
Correct: relative color syntax with a fallback
If you intentionally use CSS Color Level 5 relative color syntax and the validator flags from, provide a fallback and be aware of current browser support:
<style>
.banner {
background: rgb(255, 0, 0);
background: rgb(from red r g b / 50%);
}
</style>
<div class="banner">Relative color with fallback</div>
Always verify that your background values use standard CSS syntax. When in doubt, test your styles in the W3C CSS Validator and check browser support on Can I Use.
When the CSS parser encounters a background-image value it cannot understand, it flags a parse error. This doesn't necessarily mean the browser won't render your styles — browsers are often more forgiving than validators — but it does indicate that your CSS doesn't conform to the specification. Invalid CSS can lead to unpredictable rendering across different browsers, makes your code harder to maintain, and may cause styles to silently fail in certain environments.
Common causes of this error include:
- Missing the
url()function around image paths. - Unquoted or improperly quoted URLs containing special characters like spaces or parentheses.
- Typos in CSS function names (e.g.,
lnear-gradientinstead oflinear-gradient). - Using vendor-prefixed values (e.g.,
-webkit-linear-gradient) in contexts where the validator expects standard CSS. - Invalid gradient syntax, such as missing color stops, incorrect angle units, or malformed function arguments.
- Using CSS custom properties (variables) or newer syntax in a
styleattribute, which the validator's CSS parser may not fully support.
To fix this, review the exact background-image declaration the validator is pointing to. Make sure all URLs are wrapped in url(), all gradients use correct function names and valid arguments, and all strings are properly quoted and closed.
Examples
Missing url() function
A bare file path without the url() wrapper is invalid:
<!-- ❌ Parse error: missing url() -->
<div style="background-image: /images/hero.jpg;"></div>
Wrap the path in url():
<!-- ✅ Correct -->
<div style="background-image: url('/images/hero.jpg');"></div>
Typo in gradient function name
<!-- ❌ Parse error: misspelled function -->
<div style="background-image: lnear-gradient(to right, red, blue);"></div>
<!-- ✅ Correct -->
<div style="background-image: linear-gradient(to right, red, blue);"></div>
Invalid gradient syntax
Missing color stops or using incorrect angle notation causes parse errors:
<!-- ❌ Parse error: invalid angle unit and missing second color stop -->
<div style="background-image: linear-gradient(45, red);"></div>
Angles need a unit (like deg), and gradients need at least two color stops:
<!-- ✅ Correct -->
<div style="background-image: linear-gradient(45deg, red, blue);"></div>
Unescaped special characters in URL
File paths with spaces or parentheses need to be quoted:
<!-- ❌ Parse error: unquoted URL with spaces -->
<div style="background-image: url(/images/my hero image.jpg);"></div>
<!-- ✅ Correct: quoted URL -->
<div style="background-image: url('/images/my hero image.jpg');"></div>
Vendor-prefixed values
Using non-standard prefixed syntax can trigger a parse error in the validator:
<!-- ❌ Parse error: vendor prefix not recognized by validator -->
<div style="background-image: -webkit-linear-gradient(left, red, blue);"></div>
Use the standard, unprefixed syntax instead. Modern browsers no longer need the prefix for gradients:
<!-- ✅ Correct: standard syntax -->
<div style="background-image: linear-gradient(to right, red, blue);"></div>
Multiple backgrounds with incorrect separator
Multiple background images must be separated by commas, not semicolons or spaces:
<!-- ❌ Parse error: wrong separator -->
<div style="background-image: url('a.png') url('b.png');"></div>
<!-- ✅ Correct: comma-separated -->
<div style="background-image: url('a.png'), url('b.png');"></div>
Moving styles to an external stylesheet
If the validator struggles with complex background-image values in inline style attributes, consider moving the CSS to a <style> block or external stylesheet, where the validator's CSS parser handles them more reliably:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Background Image Example</title>
<style>
.hero {
background-image: url('hero.jpg');
background-size: cover;
}
</style>
</head>
<body>
<div class="hero"></div>
</body>
</html>
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()
<div style="background-image: hero.jpg;">
Content here
</div>
Incorrect: misspelled function name
<div style="background-image: urls('hero.jpg');">
Content here
</div>
Incorrect: missing parentheses in url
<div style="background-image: url 'hero.jpg';">
Content here
</div>
Incorrect: invalid keyword
<div style="background-image: transparent;">
Content here
</div>
Correct: using url() with a file path
<div style="background-image: url('hero.jpg');">
Content here
</div>
Correct: using none to explicitly set no background image
<div style="background-image: none;">
Content here
</div>
Correct: using a gradient function
<div style="background-image: linear-gradient(to right, #ff7e5f, #feb47b);">
Content here
</div>
Correct: multiple background images
<div style="background-image: url('overlay.png'), linear-gradient(to bottom, #000, #333);">
Content here
</div>
Correct: using a <style> block
<!DOCTYPE html>
<html lang="en">
<head>
<title>Background Image Example</title>
<style>
.banner {
background-image: url("banner.png");
background-size: cover;
background-repeat: no-repeat;
}
</style>
</head>
<body>
<div class="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.
A CSS color value (like a hex code or color name) was used where a background-image value is expected, or vice versa — the background-image property only accepts image functions such as url() or gradient functions, not plain color values.
The background-image property is specifically designed for setting images or gradients as backgrounds. If you want to set a solid background color, use the background-color property instead. Alternatively, you can use the shorthand background property, which accepts both colors and images.
This error often occurs when using the background shorthand incorrectly or when accidentally assigning a color value directly to background-image in inline styles.
Incorrect Example
<div style="background-image: #ff0000;">
This will trigger a validation error.
</div>
Correct Examples
Use background-color for solid colors:
<div style="background-color: #ff0000;">
Using background-color for a solid color.
</div>
Use background-image only for images or gradients:
<div style="background-image: url('banner.jpg');">
Using background-image with a URL.
</div>
<div style="background-image: linear-gradient(to right, #ff0000, #0000ff);">
Using background-image with a gradient.
</div>
Or use the background shorthand, which accepts both:
<div style="background: #ff0000 url('banner.jpg') no-repeat center;">
Using the background shorthand.
</div>
The linear-gradient() function went through several syntax revisions during CSS standardization. Early drafts and vendor-prefixed implementations (like -webkit-linear-gradient()) used bare direction keywords such as top, bottom left, etc., where the keyword indicated the starting point of the gradient. The final standard, defined in the CSS Images Module Level 3 and Level 4 specifications, changed this so that direction keywords use the to prefix and indicate the ending point of the gradient. For example, the old linear-gradient(top, #fff, #000) meant "start at the top and go to the bottom," while the correct modern equivalent is linear-gradient(to bottom, #fff, #000).
This matters because the old syntax without to is not valid CSS per the current specification. While some browsers may still interpret the legacy syntax for backward compatibility, relying on it is risky — behavior can vary across browsers, and it will trigger validation errors. Using standard-compliant CSS ensures consistent rendering and forward compatibility.
How to fix it
Replace the bare direction keyword with the correct to syntax. Note that the direction meaning is inverted: the old syntax specified where the gradient starts, while the new syntax specifies where it goes to.
Here's a quick mapping from old to new syntax:
| Old (invalid) | New (valid) | Angle equivalent |
|---|---|---|
top | to bottom | 180deg |
bottom | to top | 0deg |
left | to right | 90deg |
right | to left | 270deg |
top left | to bottom right | N/A (use to syntax) |
Important: Notice that top in the old syntax means "start at top, go to bottom." So the modern equivalent is to bottom, not to top. If the validator message says the argument should be to top, it means you wrote top — but be sure you understand which direction your gradient should actually go before blindly replacing it. If you truly want the gradient to go toward the top, use to top. If you want it to go from the top downward, use to bottom.
If you don't specify a direction at all, linear-gradient() defaults to to bottom (top-to-bottom), which is often what you want.
Examples
Invalid: bare direction keyword
<div style="background: linear-gradient(top, #ffffff, #000000);">
Content
</div>
The bare keyword top is not valid in the standard linear-gradient() syntax and will trigger the validator error.
Fixed: using the to keyword
<div style="background: linear-gradient(to bottom, #ffffff, #000000);">
Content
</div>
Since the old top meant "start at the top," the equivalent standard syntax is to bottom.
Fixed: using an angle
<div style="background: linear-gradient(180deg, #ffffff, #000000);">
Content
</div>
An angle of 180deg produces the same top-to-bottom gradient.
Full document example
<!DOCTYPE html>
<html lang="en">
<head>
<title>Gradient Example</title>
<style>
.box {
width: 200px;
height: 100px;
/* Valid: direction keyword with "to" */
background: linear-gradient(to top, #ffffff, #000000);
}
.box-angle {
width: 200px;
height: 100px;
/* Valid: angle equivalent of "to top" */
background: linear-gradient(0deg, #ffffff, #000000);
}
.box-default {
width: 200px;
height: 100px;
/* Valid: no direction specified, defaults to "to bottom" */
background: linear-gradient(#ffffff, #000000);
}
</style>
</head>
<body>
<div class="box"></div>
<div class="box-angle"></div>
<div class="box-default"></div>
</body>
</html>
All three approaches are valid. Choose whichever is clearest for your use case — the to keyword syntax is generally the most readable, while angles offer more precision for diagonal or non-cardinal directions.
The background CSS property is a shorthand that can accept values for background-color, background-image, background-position, background-size, background-repeat, background-origin, background-clip, and background-attachment. When the validator encounters an unrecognized value, it tries to match it against individual sub-properties like background-color. If the value doesn't match any of them, you'll see this error.
Common causes include typos in color names (e.g., bleu instead of blue), malformed hex codes (e.g., #gggggg or a missing #), incorrect function syntax (e.g., rgb(255 0 0 with a missing parenthesis), or using values that simply don't exist in CSS. This error can also appear when a CSS custom property (variable) is used in inline styles and the validator can't resolve it, or when a browser-specific value is used that isn't part of the CSS specification.
Fixing this issue ensures your styles render predictably across browsers. While browsers are often forgiving and may ignore invalid declarations silently, relying on that behavior can lead to inconsistent rendering. Standards-compliant CSS is easier to maintain and debug.
How to Fix
- Check for typos in color names, hex codes, or function syntax.
- Verify the value format — hex colors need a
#prefix,rgb()andrgba()need proper comma-separated or space-separated values with closing parentheses. - Use
background-colorinstead of the shorthandbackgroundif you only intend to set a color. This makes your intent clearer and reduces the chance of conflicting shorthand values. - Remove vendor-prefixed or non-standard values that the validator doesn't recognize.
Examples
Incorrect — Typo in color name
<div style="background: aquaa;">Content</div>
aquaa is not a valid CSS color name, so the validator rejects it.
Correct — Valid color name
<div style="background: aqua;">Content</div>
Incorrect — Malformed hex code
<div style="background: #xyz123;">Content</div>
Hex color codes only allow characters 0–9 and a–f.
Correct — Valid hex code
<div style="background: #00a123;">Content</div>
Incorrect — Missing hash symbol
<div style="background: ff0000;">Content</div>
Without the #, the validator interprets ff0000 as an unknown keyword.
Correct — Hex code with hash
<div style="background: #ff0000;">Content</div>
Incorrect — Broken rgb() syntax
<div style="background: rgb(255, 0, 300);">Content</div>
RGB channel values must be between 0 and 255 (or 0% to 100%).
Correct — Valid rgb() value
<div style="background: rgb(255, 0, 128);">Content</div>
Correct — Using background-color for clarity
When you only need to set a color, prefer the specific background-color property over the shorthand:
<div style="background-color: rgba(255, 0, 0, 0.5);">Semi-transparent red</div>
Correct — Valid shorthand with image and other properties
<div style="background: url('image.jpg') no-repeat center / cover;">Content</div>
Note the / between background-position (center) and background-size (cover) — this is required syntax in the shorthand.
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 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>
<div class="box">Content</div>
Correct: removing rounded corners with 0
<style>
.box {
border-radius: 0;
}
</style>
<div class="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>
<div class="circle">Circle</div>
<div class="rounded">Rounded</div>
<div class="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>
<div class="card">Rounded card</div>
<div class="card sharp">Sharp-cornered card</div>
Validate at scale.
Ship accessible websites, faster.
Automated HTML & accessibility validation for large sites. Check thousands of pages against WCAG guidelines and W3C standards in minutes, not days.
Pro Trial
Full Pro access. Cancel anytime.
Start Pro Trial →Join teams across 40+ countries