https://github.com/trananhtung/specificity
Calculate the CSS specificity (a, b, c) of a selector — :is/:not/:has/:where aware. A Rust take on the specificity npm package. Zero deps, no_std.
https://github.com/trananhtung/specificity
cascade css no-std rust selector specificity
Last synced: 5 days ago
JSON representation
Calculate the CSS specificity (a, b, c) of a selector — :is/:not/:has/:where aware. A Rust take on the specificity npm package. Zero deps, no_std.
- Host: GitHub
- URL: https://github.com/trananhtung/specificity
- Owner: trananhtung
- License: apache-2.0
- Created: 2026-06-22T05:30:13.000Z (12 days ago)
- Default Branch: master
- Last Pushed: 2026-06-22T14:47:44.000Z (11 days ago)
- Last Synced: 2026-06-22T16:26:46.555Z (11 days ago)
- Topics: cascade, css, no-std, rust, selector, specificity
- Language: Rust
- Size: 15.6 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE-APACHE
Awesome Lists containing this project
README
# specificity
[](#contributors-)
[](https://crates.io/crates/specificity)
[](https://docs.rs/specificity)
[](https://github.com/trananhtung/specificity/actions/workflows/ci.yml)
[](#license)
**Calculate the CSS specificity `(a, b, c)` of a selector** — `a` for ID selectors,
`b` for classes/attributes/pseudo-classes, `c` for type selectors/pseudo-elements.
Modern selectors are handled per the
[spec](https://www.w3.org/TR/selectors-4/#specificity-rules). The Rust counterpart of
the [`specificity`](https://www.npmjs.com/package/specificity) npm package. Zero
dependencies and `#![no_std]`.
```rust
use specificity::{specificity, Specificity};
assert_eq!(specificity("#id .cls a"), Specificity::new(1, 1, 1));
assert_eq!(specificity(":is(.a, #b)"), Specificity::new(1, 0, 0)); // max of the args
assert_eq!(specificity(":where(.a)"), Specificity::new(0, 0, 0)); // contributes nothing
// Specificity is `Ord`, so selectors compare directly.
assert!(specificity("#id") > specificity(".a.b.c"));
```
## Why specificity?
CSS linters, cascade-analysis tools, devtools, and CSS-in-JS engines all need to
know how strongly a selector matches. The rules are small but full of corners
(`:is`/`:not`/`:has` take the most specific argument, `:where` is free, `::part`
ignores its argument, namespaces and escapes don't fool the counter). Rust had this
only buried inside full CSS engines; this is the focused, dependency-free piece.
```toml
[dependencies]
specificity = "0.1"
```
## API
| Item | Purpose |
| --- | --- |
| `specificity(selector)` | The `Specificity` of a single complex selector (max of a list) |
| `specificity_list(list)` | One `Specificity` per comma-separated selector |
| `Specificity { a, b, c }` | The components; implements `Ord` (a, then b, then c) and `Display` (`"a,b,c"`) |
## Behavior
- `a` = ID selectors; `b` = classes, attribute selectors, pseudo-classes;
`c` = type selectors and pseudo-elements. The universal `*` and combinators add
nothing.
- `:is()`, `:not()`, `:has()` (and `:matches()`/`:-*-any()`) contribute the
specificity of their **most specific** argument; `:where()` contributes nothing.
- `:nth-child()`/`:nth-last-child()` are pseudo-classes; an `… of S` argument adds
the most specific selector in `S`.
- Pseudo-elements (`::before`, `::part(x)`, the legacy single-colon `:before`, …)
count as `c`, and their functional arguments are ignored.
- Namespace prefixes (`svg|a`, `*|div`) and CSS escapes (`.foo\.bar`) are parsed
correctly, and CSS `/* … */` comments are ignored.
## Differences from the npm package
Where keeganstreet `specificity` diverges from the CSS spec, this crate follows the
spec: `:matches()` / `:-*-any()` are treated as aliases of `:is()` (most specific
argument, not a plain pseudo-class), and a namespaced universal such as `*|*`
contributes nothing. CSS Modules' `:global()` / `:local()` are supported, taking
their argument's specificity.
## Contributors ✨
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind are welcome — code, docs, bug reports, ideas, reviews! See the [emoji key](https://allcontributors.org/docs/en/emoji-key) for how each contribution is recognized, and open a PR or issue to get involved.
Thanks goes to these wonderful people:
## License
Licensed under either of [Apache-2.0](LICENSE-APACHE) or [MIT](LICENSE-MIT) at
your option.