About This CSS Issue
CSS pseudo-classes (like :hover, :focus, :nth-child()) select elements based on their state or position, while pseudo-elements (like ::before, ::after, ::placeholder) target specific parts of an element. The CSS specification distinguishes between the two by using a single colon for pseudo-classes and a double colon for pseudo-elements. While browsers still support the legacy single-colon syntax for older pseudo-elements like :before and :after for backward compatibility, the validator expects the modern double-colon form ::before and ::after.
Why This Matters
Standards compliance. The double-colon syntax for pseudo-elements was introduced in CSS3 to clearly distinguish pseudo-elements from pseudo-classes. Using the correct syntax makes your code more readable and future-proof.
Catching real bugs. A misspelled pseudo-class like :foucs or :hovr will silently fail — the browser simply ignores the entire rule. The validator catches these typos before they cause mysterious styling issues in production.
Validator profile limitations. The W3C CSS validator checks your styles against a specific CSS profile. Newer selectors like :has(), :is(), or :where() may not be recognized if the validator is set to an older profile like CSS Level 2.1 or even CSS Level 3. Vendor-prefixed selectors like ::-webkit-input-placeholder or ::-moz-placeholder are never part of any standard profile and will always be flagged.
Common Causes
-
Typos —
:hovr,:foucs,::plceholder, etc. -
Single colon on pseudo-elements —
:before,:after,:first-line,:first-letterinstead of their double-colon equivalents. -
Vendor-prefixed selectors —
::-webkit-input-placeholder,::-moz-selection,:-ms-input-placeholder. -
Modern selectors on older profiles —
:has(),:is(),:where(),::marker,:focus-visiblemay not be recognized depending on the validator’s CSS level setting.
How to Fix
- Check spelling of all pseudo-classes and pseudo-elements.
-
Use double colons for pseudo-elements:
::before,::after,::first-line,::first-letter,::placeholder,::marker,::selection. - Replace vendor-prefixed selectors with their standard equivalents. If you still need the prefix for browser support, place the standard version alongside it and accept that the prefixed line may produce a warning.
-
Update the validator profile to a newer CSS level if you’re intentionally using modern selectors like
:has()or:focus-visible.
Examples
Incorrect — triggers the warning
<style>
/* Typo in pseudo-class */
a:hovr {
color: red;
}
/* Single colon on pseudo-element */
p:before {
content: "→ ";
}
/* Vendor-prefixed pseudo-element without standard version */
input::-webkit-input-placeholder {
color: gray;
}
</style>
Each of these rules will trigger an “Unknown pseudo-element or pseudo-class” warning. The first is a simple typo, the second uses outdated single-colon syntax, and the third is a non-standard vendor prefix.
Correct — valid CSS
<style>
/* Fixed typo */
a:hover {
color: red;
}
/* Double colon for pseudo-element */
p::before {
content: "→ ";
}
/* Standard pseudo-element */
input::placeholder {
color: gray;
}
</style>
Handling modern selectors
Some modern pseudo-classes like :has() and :focus-visible are well-supported in browsers but may not yet be recognized by the validator. If you need to use them, you can acknowledge the warning or structure your CSS so the modern selector enhances rather than replaces base styles:
<style>
/* Base style that always applies */
.card {
border: 1px solid transparent;
}
/* Enhancement using :has() — may warn in the validator */
.card:has(img) {
border-color: #ccc;
}
/* :focus-visible for keyboard-only focus rings */
button:focus-visible {
outline: 2px solid blue;
}
</style>
These selectors are valid CSS and work in modern browsers. If the validator flags them, consider switching the validator’s profile to the latest CSS level, or treat the warnings as informational rather than errors.
Find issues like this automatically
Rocket Validator scans thousands of pages in seconds, detecting HTML issues across your entire site.