1001Ferramentas
๐ŸŽจValidators

CSS Selector Validator

Verify whether a CSS selector is valid and compute its specificity (a,b,c). Lists detected classes, IDs and elements.

โ€”

CSS selector validation: from syntax to specificity

A CSS selector is the pattern that picks DOM nodes for styling or scripting. Validation has two layers: syntax (does the selector parse?) and semantics (does it select what the author intended?). The W3C spec Selectors Level 4 standardizes the grammar; browsers implement it through WebKit (Safari), Blink (Chrome, Edge, Opera) and Gecko (Firefox). The runtime test is simple: document.querySelector(selector) throws a SyntaxError on invalid input, so any validator can wrap it in try/catch.

Selector types and combinators

  • Element: div, p, a โ€” by tag name.
  • Class: .btn, .card โ€” by class attribute.
  • ID: #main, #nav โ€” by id, must be unique.
  • Attribute: [type="text"], [href^="https"], [data-id].
  • Pseudo-class: :hover, :focus, :nth-child(2n+1), :not(.x), :has(> img).
  • Pseudo-element: ::before, ::after, ::placeholder, ::selection.
  • Descendant: a b (any depth) vs child: a > b (direct child only).
  • Adjacent sibling: a + b (immediately after) vs general sibling: a ~ b (any later sibling).

Specificity calculation

When two rules target the same element, the higher specificity wins. The classic formula is (a, b, c) read as a three-digit number: a = number of IDs, b = classes + attribute selectors + pseudo-classes, c = elements + pseudo-elements. Inline styles add a fourth, higher field; !important overrides the whole calculation but should be a last resort.

#main .card a:hover  โ†’  (1, 2, 1)  โ†’  121
.btn.primary         โ†’  (0, 2, 0)  โ†’  020
ul li                โ†’  (0, 0, 2)  โ†’  002
div > .item::before  โ†’  (0, 1, 2)  โ†’  012

A common gotcha: :not(), :is() and :where() change the rules. :where() contributes zero specificity regardless of its argument โ€” extremely useful for resets that you want easy to override. :is() contributes the specificity of its most specific argument.

Browser support and :has()

Most CSS Selectors Level 4 features are stable across modern browsers, but a few are recent. :has() โ€” the "parent selector" โ€” landed in Chrome 105 (Aug 2022), Safari 15.4 (Mar 2022) and Firefox 121 (Dec 2023). Before relying on it in production, check usage telemetry (caniuse.com/css-has) and gate it behind @supports selector(:has(*)). :focus-visible, :focus-within, ::backdrop are now safe on all evergreen browsers.

Use cases beyond styling

  • DOM query in JS: document.querySelector, querySelectorAll, element.matches, element.closest.
  • E2E testing: Cypress (cy.get('selector')), Playwright (page.locator('selector')), Puppeteer (page.$(selector)).
  • Web scraping: Cheerio (Node), BeautifulSoup with select() (Python), Goquery (Go).
  • Legacy jQuery: the Sizzle engine extended CSS with non-standard pseudos (:contains, :visible) that don't work in querySelector.

Performance and anti-patterns

Browsers match selectors right-to-left, so the rightmost piece (the key selector) drives initial filtering. getElementById is the fastest lookup; querySelector('#id') is marginally slower because it parses the selector first. Long descendant chains like body > div > div > main > article > section > h2.title are fragile โ€” any markup change breaks them. The best practice for E2E tests is to use data attributes as stable hooks: [data-testid="submit-button"]. They decouple test code from styling and survive refactors.

FAQ

Can I test :has() in this validator? Yes, as long as you run it in a modern browser. The validator delegates to document.querySelector, so if your browser supports :has() the validator does too.

How do I select a parent element? Use :has(): div:has(> img) matches divs that contain a direct-child image. Before :has() shipped, the only option was JavaScript traversal (element.parentElement).

For E2E tests, should I prefer CSS or XPath? CSS. Playwright, Cypress and modern QA tooling treat CSS as first class; XPath is more powerful (full text search, ancestor axis) but verbose and slow. Reach for XPath only when CSS cannot express the query.

Does :scope work in querySelector? Yes. element.querySelectorAll(':scope > li') matches only direct-child li of element, avoiding the historical bug where the selector starts from the document.

Why does my selector with quotes fail? Probably nested quoting. '[data-x="a"]' is fine; "[data-x=\"a\"]" needs escaping. In CSS-in-JS templates, prefer single-quoted strings or backtick literals to avoid escape sequences.

Related Tools