{"id":18887669,"url":"https://github.com/bramus/specificity","last_synced_at":"2025-04-04T08:05:50.063Z","repository":{"id":40350400,"uuid":"462530019","full_name":"bramus/specificity","owner":"bramus","description":"JavaScript Package to calculate the Specificity of CSS Selectors","archived":false,"fork":false,"pushed_at":"2025-02-18T20:29:05.000Z","size":903,"stargazers_count":85,"open_issues_count":1,"forks_count":6,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-03-28T07:08:37.651Z","etag":null,"topics":["css","javascript","specificity"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bramus.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"bramus","-custom":["https://www.paypal.me/bramus","https://www.bram.us/"]}},"created_at":"2022-02-23T00:56:04.000Z","updated_at":"2025-03-15T13:53:17.000Z","dependencies_parsed_at":"2024-02-18T14:25:29.054Z","dependency_job_id":"e577b300-4e9d-452c-9904-1dd076298ff8","html_url":"https://github.com/bramus/specificity","commit_stats":{"total_commits":106,"total_committers":5,"mean_commits":21.2,"dds":0.07547169811320753,"last_synced_commit":"5c84df3e56dd6941fff1f120fed1b123bd30f54a"},"previous_names":[],"tags_count":25,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bramus%2Fspecificity","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bramus%2Fspecificity/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bramus%2Fspecificity/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bramus%2Fspecificity/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bramus","download_url":"https://codeload.github.com/bramus/specificity/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247142063,"owners_count":20890652,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["css","javascript","specificity"],"created_at":"2024-11-08T07:38:52.830Z","updated_at":"2025-04-04T08:05:50.038Z","avatar_url":"https://github.com/bramus.png","language":"JavaScript","funding_links":["https://github.com/sponsors/bramus","https://www.paypal.me/bramus","https://www.bram.us/"],"categories":[],"sub_categories":[],"readme":"[![Calculate CSS Specificity](./screenshots/calculate-specificity.png)](https://codepen.io/bramus/pen/WNXyoYm)\n\n# Specificity\n\n`@bramus/specificity` is a package to calculate the specificity of CSS Selectors. It also includes some convenience functions to compare, sort, and filter an array of specificity values.\n\nSupports [Selectors Level 4](https://www.w3.org/TR/selectors-4/), including those special cases `:is()`, `:where()`, `:not()`, etc.\n\nDemo: [https://codepen.io/bramus/pen/WNXyoYm](https://codepen.io/bramus/pen/WNXyoYm)\n\n## Installation\n\n```bash\nnpm i @bramus/specificity\n```\n\n## Usage / Example\n\nAt its core, `@bramus/specificity` exposes a `Specificity` class. Its static `calculate` method can be used to calculate the specificity of a given CSS [Selector List](https://www.w3.org/TR/selectors-4/#grouping) string.\n\n```js\nimport Specificity from '@bramus/specificity';\n\nconst specificities = Specificity.calculate('header:where(#top) nav li:nth-child(2n), #doormat');\n```\n\nBecause `calculate` accepts a [Selector List](https://www.w3.org/TR/selectors-4/#grouping) — which can contain more than 1 [Selector](https://www.w3.org/TR/selectors-4/#selector) — it will always return an array, with each entry being a `Specificity` instance — one per found selector.\n\n```js\nconst specificities = Specificity.calculate('header:where(#top) nav li:nth-child(2n), #doormat');\nspecificities.map((s) =\u003e s.toString()); // ~\u003e [\"(0,1,3)\",\"(1,0,0)\"]\n```\n\n💡 If you know you’re passing only a single Selector into `calculate()`, you can use JavaScript’s built-in destructuring to keep your variable names clean.\n\n```js\nconst [s] = Specificity.calculate('header:where(#top) nav li:nth-child(2n)');\ns.toString(); // ~\u003e \"(0,1,3)\"\n```\n\n💡 Under the hood, `@bramus/specificity` uses [CSSTree](https://github.com/csstree/csstree) to do the parsing of strings to Selectors. As a result, the `calculate` method also accepts a [CSSTree AST](https://github.com/csstree/csstree/blob/master/docs/ast.md) of the types `Selector` and `SelectorList`.\n\nIf you have a pre-parsed CSSTree AST of the type `Selector` you can pass it into `Specificity.calculateForAST()`. It [performs slightly better](#benchmark) than `Specificity.calculate()` as it needs to check fewer things. It differs from `Specificity.calculate()` in that it does not return an array of `Specificity` instances but only a single value.\n\n## The Return Format\n\nA calculated specificity is represented as an instance of the `Specificity` class. The `Specificity` class includes methods to get the specificity value in a certain format, along with some convenience methods to compare it against other instances.\n\n```js\n// 🚀 Thunderbirds are go!\nimport Specificity from '@bramus/specificity';\n\n// ✨ Calculate specificity for each Selector in the given Selector List\nconst specificities = Specificity.calculate('header:where(#top) nav li:nth-child(2n), #doormat');\n\n// 🚚 The values in the array are instances of the Specificity class\nconst s = specificities[0]; // Instance of Specificity\n\n// 👀 Read the specificity value using one of its accessors\ns.value; // { a: 0, b: 1, c: 3 }\ns.a; // 0\ns.b; // 1\ns.c; // 3\n\n// 🛠 Convert the calculated value to various formats using one of the toXXX() instance methods\ns.toString(); // \"(0,1,3)\"\ns.toArray(); // [0, 1, 3]\ns.toObject(); // { a: 0, b: 1, c: 3 }\n\n// 💡 Extract the matched selector string\ns.selectorString(); // \"header:where(#top) nav li:nth-child(2n)\"\n\n// 🔀 Use one of its instance comparison methods to compare it to another Specificity instance\ns.isEqualTo(specificities[1]); // false\ns.isGreaterThan(specificities[1]); // false\ns.isLessThan(specificities[1]); // true\n\n// 💻 Don’t worry about JSON.stringify()\nJSON.stringify(s);\n// {\n//    \"selector\": 'header:where(#top) nav li:nth-child(2n)',\n//    \"asObject\": { \"a\": 0, \"b\": 1, \"c\": 3 },\n//    \"asArray\": [0, 1, 3],\n//    \"asString\": \"(0,1,3)\",\n// }\n```\n\n## Utility Functions (Static Methods)\n\nThis package also exposes some utility functions to work with specificities. These utility functions are all exposed as static methods on the `Specificity` class.\n\n-   Comparing:\n\n    -   `Specificity.compare(s1, s2)`: Compares s1 to s2. Returns a value that can be:\n        -   `\u003e 0` = Sort s2 before s1 _(i.e. s1 is more specific than s2)_\n        -   `0` = Keep original order of s1 and s2 _(i.e. s1 and s2 are equally specific)_\n        -   `\u003c 0` = Sort s1 before s2 _(i.e. s1 is less specific than s2)_\n    -   `Specificity.equals(s1, s2)`: Returns `true` if s1 and s2 have the same specificity. If not, `false` is returned.\n    -   `Specificity.greaterThan(s1, s2)`: Returns `true` if s1 has a higher specificity than s2. If not, `false` is returned.\n    -   `Specificity.lessThan(s1, s2)`: Returns `true` if s1 has a lower specificity than s2. If not, `false` is returned.\n\n-   Sorting:\n\n    -   `Specificity.sortAsc(s1, s2, …, sN)`: Sorts the given specificities in ascending order _(low specificity to high specificity)_\n    -   `Specificity.sortDesc(s1, s2, …, sN)`: Sorts the given specificities in descending order _(high specificity to low specificity)_\n\n-   Filtering:\n    -   `Specificity.min(s1, s2, …, sN)`: Filters out the value with the lowest specificity\n    -   `Specificity.max(s1, s2, …, sN)`: Filters out the value with the highest specificity\n\nA specificity passed into any of these utility functions can be any of:\n\n-   An instance of the included `Specificity` class\n-   A simple Object such as `{'a': 1, 'b': 0, 'c': 2}`\n\n## Utility Functions (Standalone)\n\nAll static methods the `Specificity` class exposes are also exported as standalone functions using [Subpath Exports](https://nodejs.org/api/packages.html#subpath-exports).\n\nIf you're only interested in including some of these functions into your project you can import them from their Subpath. As a result, your bundle size will be reduced greatly _(except for including the standalone `calculate`, as it returns an array of `Specificity` instances that relies on the whole lot)_\n\n```js\nimport { calculate, calculateForAST } from '@bramus/specificity/core';\nimport { compare, equals, greaterThan, lessThan } from '@bramus/specificity/compare';\nimport { min, max } from '@bramus/specificity/filter';\nimport { sortAsc, sortDesc } from '@bramus/specificity/sort';\n```\n\n## Type Definitions\n\nAlthough `@bramus/specificity` is written in Vanilla JavaScript, it does include [Type Definitions](https://www.typescriptlang.org/docs/handbook/2/type-declarations.html) which are exposed via its `package.json`.\n\n## Binary/CLI\n\n`@bramus/specificity` exposes a binary named `specificity` to calculate the specificity of a given selector list on the CLI. For each selector that it finds, it'll print out the calculated specificity as a string on a new line.\n\n```bash\n$ specificity \"header:where(#top) nav li:nth-child(2n), #doormat\"\n(0,1,3)\n(1,0,0)\n```\n\n## Benchmark\n\nA benchmark is included, which you can invoke using `npm run benchmark`.\n\nSample results (tested on a MacBook Air M3):\n\n```\nSpecificity.calculate(string) x 420,682 ops/sec ±0.34% (98 runs sampled)\nSpecificity.calculate(ast) - using SelectorList x 8,994,080 ops/sec ±0.25% (98 runs sampled)\nSpecificity.calculate(ast) - using Selector x 11,054,856 ops/sec ±0.39% (91 runs sampled)\nSpecificity.calculateForAST(ast) x 12,652,322 ops/sec ±0.35% (96 runs sampled)\n```\n\n## License\n\n`@bramus/specificity` is released under the MIT public license. See the enclosed `LICENSE` for details.\n\n## Acknowledgements\n\nThe idea to create this package was sparked by [the wonderful Specificity Calculator created by Kilian Valkhof / Polypane](https://polypane.app/css-specificity-calculator/), a highly educational tool that not only calculates the specificity, but also explains which parts are responsible for it.\n\nThe heavy lifting of doing the actual parsing of Selectors is done by [CSSTree](https://github.com/csstree/csstree).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbramus%2Fspecificity","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbramus%2Fspecificity","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbramus%2Fspecificity/lists"}