Proposal: CSS `specificity` Property for Explicit Selector Weight

Hi CSSWG,

I propose a new CSS property, `specificity`, to allow developers to
explicitly set a selector's weight, addressing the pain points of the
current specificity system that force artificial selector conditions.

Problem
-------
The current CSS specificity system (IDs=100, classes=10, elements=1) often
requires developers to use hacks to achieve desired precedence, such as:
- Repeating classes (e.g., `td.status.status.status` for 0-3-1) to override
selectors like `.table td.status` (0-1-1).
- Adding artificial selectors (e.g., `#dummy`, `.body .table td.status`) to
boost specificity.
- Overusing `!important`, which creates maintenance issues and lacks
granularity.

These practices lead to:
- Unmaintainable, verbose CSS that obscures intent.
- Semantic noise from meaningless selector chains.
- Debugging challenges, as developers must manually calculate specificity
scores.
- Escalating specificity wars in large or legacy codebases.

Proposed Solution
-----------------
Introduce a `specificity` property to set a selector's weight directly:

  td.status {
    specificity: 300;
    border: solid 1px blue;
  }

- Value: `<integer>` (non-negative, e.g., 300 = three classes) or `auto`
(default, uses traditional specificity).
- Applies to: All elements.
- Computed value: As specified.
- Cascade: Overrides the selector's calculated specificity in the cascade
algorithm.

Examples
--------
1. Override a more specific selector:
   .table td.status { /* Specificity: 0-1-1 = 110 */
     border: solid 1px red;
   }
   td.status { /* Specificity: 300 */
     specificity: 300;
     border: solid 1px blue;
   }
   Result: `td.status` wins without hacks like `td.status.status.status`.

2. Fine-grained control:
   td.status { /* Specificity: 200 */
     specificity: 200;
     border: solid 1px blue;
   }
   .table td.status { /* Specificity: 0-1-1 = 110 */
     border: solid 1px red;
   }
   Result: `td.status` overrides without artificial selectors.

Benefits
--------
- Eliminates hacks like class repetition or dummy IDs.
- Simplifies debugging by making specificity explicit.
- Offers precise control without altering selector semantics.
- Complements `@layer` and `@scope` for comprehensive cascade management.

Challenges and Mitigations
-------------------------
1. Backward Compatibility:
   - Default to `auto` for traditional specificity.
   - Unsupported browsers ignore `specificity`, falling back to standard
rules.
   - Use `@supports` for progressive enhancement.

2. Potential Abuse:
   - Cap maximum value (e.g., 10000) to prevent excessive weights.
   - Encourage `@layer` for large-scale priority management.

3. Implementation:
   - Treat `specificity` as an override to calculated specificity, applied
before cascade resolution.
   - Display in DevTools alongside traditional specificity scores.

Integration with Cascade
-----------------------
- Sort rules by origin and importance (`!important` vs. non-`!important`).
- Within each group, use `specificity` property (if set) or traditional
specificity.
- Resolve ties by source order.

Prior Art
---------
- Issue #5057 (Selector Boundary): Related but focuses on selector
matching, not explicit weights.
- `@layer`: Manages group priority, not individual selectors.
- `:is()`/`:where()`: Adjusts specificity indirectly, not numerically.

Call to Action
--------------
I propose adding `specificity` to CSS Cascade Level 6 or a new spec.
Seeking feedback on:
- Syntax (`specificity` vs. `weight`/`rule_weight`).
- Interaction with `@layer`, `@scope`, and `!important`.
- Implementation feasibility and browser concerns.


Thanks,
Jose A. Cano

P.S. I’m sharing this on X and DEV Community to gather developer feedback.
Suggestions welcome!

Received on Thursday, 14 August 2025 14:04:26 UTC