postcss-set-specificity
- Set selector specificity to equal another's
/* Input */
@set-specificity :root {
#id::before {
content: "earlier, more specific selector should not match";
}
.class::before {
content: "later, less specific selector should match";
}
}
@set-specificity {
.a, .b, .c {
--test: "";
}
}
/* Output */
:is(*,:not(._)):where(#id)::before {
content: "earlier, more specific selector should not match";
}
:is(*,:not(._)):where(.class)::before {
content: "later, less specific selector should match";
}
:where(.a), :where(.b), :where(.c) {
--test: "";
}
npm i -D postcss-set-specificity
postcss.config.js
module.exports = {
plugins: [
require("postcss-set-specificity") // After nesting plugin, if used
]
}
Consult PostCSS documentation for alternative usage.
Requires support for these CSS Selectors Level 4 features:
This corresponds to a browserslist roughly like:
Chrome >= 88
Safari >= 14
Firefox >= 78
Given that:
:is()
and:not()
have specificities equal to the maximum specificity within them:is(*, :not(x))
matches like the universal selector (*
), but with the specificity ofx
:where()
always has a specificity of zero:is(*, :not(x)):where(y)
matches likey
, but with the specificity ofx
- the specificity of a selector can be matched in an optimal way:
element#id.class:pseudo-class[attribute]::pseudo-element element *
=>1,3,3
_+_+_#_._._._
=>1,3,3
- pseudo elements can't be used in
:where()
,:is()
, or:not()
If provided with:
@set-specificity x {
y::before {}
}
The plugin produces:
:is(*,:not(_)):where(y)::before {}
In cases where there is no selector provided, we can simply use :where()
alone.
- Does not yet interoperate with CSS Nesting, but wouldn't be hard to with
@nest
. - Pseudo elements are treated as exceptions and add
0,0,1
to the specificity, as they cannot be set to zero, and simply subtracting will lead to inconsistency. - Pseudo elements must be written with the
::
prefix instead of with their old:
prefix
- Calculate specificities
- Partial shared specificity
:is(*,:not(a#b.c)):where(d#e)
tod#e:is(*,:not(.c))
- Full shared specificity
:is(*,:not(a#b.c)):where(d#e.f)
tod#e.f
- Partial shared specificity
- Parse selector lists for correctness
- Valid selector list (invalid selector lists would not fail because
:where()
is supposed to be forgiving):where(.a), :where(.b), :where(.c)
to:where(.a,.b,.c)
- Valid selector list (invalid selector lists would not fail because
- Assumptions/loose behavior
- Assume selector never to match
:is(*,:not(#🔝)):where(.a)
to:not(#🔝):where(.a)
- Assume selector will always match (e.g. must use something like
<html id="🔝" class="🔝">
):is(*,:not(#_)):where(.a)
to#🔝 :where(.a)
- Assume selector never to match