UNPKG

4.6 kBMarkdownView Raw
1# no-descending-specificity
2
3Disallow selectors of lower specificity from coming after overriding selectors of higher specificity.
4
5<!-- prettier-ignore -->
6```css
7 #container a { top: 10px; } a { top: 0; }
8/** ↑ ↑
9 * The order of these selectors represents descending specificity */
10```
11
12Source order is important in CSS, and when two selectors have the _same_ specificity, the one that occurs _last_ will take priority. However, the situation is different when one of the selectors has a _higher_ specificity. In that case, source order does _not_ matter: the selector with higher specificity will win out even if it comes first.
13
14The clashes of these two mechanisms for prioritization, source order and specificity, can cause some confusion when reading stylesheets. If a selector with higher specificity comes _before_ the selector it overrides, we have to think harder to understand it, because it violates the source order expectation. **Stylesheets are most legible when overriding selectors always come _after_ the selectors they override.** That way both mechanisms, source order and specificity, work together nicely.
15
16This rule enforces that practice _as best it can_, reporting fewer errors than it should. It cannot catch every _actual_ overriding selector, but it can catch certain common mistakes.
17
18## How it works
19
20**This rule looks at the last _compound selector_ in every full selector, and then compares it with other selectors in the stylesheet that end in the same way.**
21
22So `.foo .bar` (whose last compound selector is `.bar`) will be compared to `.bar` and `#baz .bar`, but not to `#baz .foo` or `.bar .foo`.
23
24And `a > li#wag.pit` (whose last compound selector is `li#wag.pit`) will be compared to `div li#wag.pit` and `a > b > li + li#wag.pit`, but not to `li` or `li #wag`, etc.
25
26Selectors targeting pseudo-elements are not considered comparable to similar selectors without the pseudo-element, because they target other elements on the rendered page. For example, `a::before {}` will not be compared to `a:hover {}`, because `a::before` targets a pseudo-element whereas `a:hover` targets the actual `<a>`.
27
28This rule only compares rules that are within the same media context. So `a {} @media print { #baz a {} }` is fine.
29
30This rule resolves nested selectors before calculating the specificity of the selectors.
31
32## DOM Limitations
33
34The linter can only check the CSS to check for specificity order. It does not have access to the HTML or DOM in order to interpret the use of the CSS.
35
36This can lead to valid linting errors appearing to be invalid at first glance.
37
38For example the following will cause an error:
39
40<!-- prettier-ignore -->
41```css
42.component1 a {}
43.component1 a:hover {}
44.component2 a {}
45```
46
47This is a correct error because the `a:hover` on line 2 has a higher specificity than the `a` on line 3.
48
49This may lead to confusion because "the two selectors will never match the same `a` in the DOM". However, since the linter does not have access to the DOM it can not evaluate this, and therefore correctly reports the error about descending specificity.
50
51It may be possible to restructure your CSS to remove the error, otherwise it is recommended that you disable the rule for that line and leave a comment saying why the error should be ignored. Note that disabling the rule will cause additional valid errors from being reported.
52
53## Options
54
55### `true`
56
57The following patterns are considered violations:
58
59<!-- prettier-ignore -->
60```css
61b a {}
62a {}
63```
64
65<!-- prettier-ignore -->
66```css
67a + a {}
68a {}
69```
70
71<!-- prettier-ignore -->
72```css
73b > a[foo] {}
74a[foo] {}
75```
76
77<!-- prettier-ignore -->
78```css
79a {
80 & > b {}
81}
82b {}
83```
84
85<!-- prettier-ignore -->
86```css
87@media print {
88 #c a {}
89 a {}
90}
91```
92
93The following patterns are _not_ considered violations:
94
95<!-- prettier-ignore -->
96```css
97a {}
98b a {}
99```
100
101<!-- prettier-ignore -->
102```css
103a {}
104a + a {}
105```
106
107<!-- prettier-ignore -->
108```css
109a[foo] {}
110b > a[foo] {}
111```
112
113<!-- prettier-ignore -->
114```css
115b {}
116a {
117 & > b {}
118}
119```
120
121<!-- prettier-ignore -->
122```css
123a::before {}
124a:hover::before {}
125a {}
126a:hover {}
127```
128
129<!-- prettier-ignore -->
130```css
131@media print {
132 a {}
133 #c a {}
134}
135```
136
137<!-- prettier-ignore -->
138```css
139a {}
140@media print {
141 #baz a {}
142}
143```
144
145### `ignore: ["selectors-within-list"]`
146
147Ignores selectors within list of selectors.
148
149The following patterns are considered violations:
150
151<!-- prettier-ignore -->
152```css
153b a {}
154h1 {}
155h2 {}
156h3 {}
157a {}
158```
159
160The following patterns are _not_ considered violations:
161
162<!-- prettier-ignore -->
163```css
164b a {}
165h1, h2, h3, a {}
166```