@codelaw/rules-css 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +23 -0
- package/NOTICE +45 -0
- package/README.md +181 -2
- package/codelaw-pack.toml +6 -0
- package/data/css/at-rules.json +97 -0
- package/data/css/deprecated.json +178 -0
- package/data/css/descriptors.json +121 -0
- package/data/css/functions.json +49 -0
- package/data/css/keywords.json +332 -0
- package/data/css/media.json +271 -0
- package/data/css/prefixed.json +266 -0
- package/data/css/properties-groups.json +183 -0
- package/data/css/properties.json +1326 -0
- package/data/css/property-keywords.json +394 -0
- package/data/css/selectors.json +281 -0
- package/data/css/shorthands.json +351 -0
- package/data/css/type-selectors.json +447 -0
- package/data/css/units.json +123 -0
- package/package.json +14 -4
- package/presets/css/conventions.toml +4 -0
- package/presets/css/recommended.toml +44 -0
- package/presets/css/standard.toml +31 -0
- package/rules/css/alpha-value-notation.cases.md +37 -0
- package/rules/css/alpha-value-notation.md +44 -0
- package/rules/css/annotation-no-unknown.md +44 -0
- package/rules/css/at-rule-descriptor-no-unknown.md +46 -0
- package/rules/css/at-rule-descriptor-value-no-unknown.md +50 -0
- package/rules/css/at-rule-no-deprecated.cases.md +13 -0
- package/rules/css/at-rule-no-deprecated.md +47 -0
- package/rules/css/at-rule-no-unknown.cases.md +25 -0
- package/rules/css/at-rule-no-unknown.md +49 -0
- package/rules/css/at-rule-no-vendor-prefix.md +44 -0
- package/rules/css/at-rule-prelude-no-invalid.md +52 -0
- package/rules/css/block-no-redundant-nested-style-rules.md +40 -0
- package/rules/css/color-function-alias-notation.md +42 -0
- package/rules/css/color-function-notation.md +42 -0
- package/rules/css/color-hex-length.cases.md +13 -0
- package/rules/css/color-hex-length.md +41 -0
- package/rules/css/comment-no-empty.md +38 -0
- package/rules/css/container-name-pattern.md +45 -0
- package/rules/css/custom-media-pattern.md +41 -0
- package/rules/css/custom-property-no-missing-var-function.cases.md +61 -0
- package/rules/css/custom-property-no-missing-var-function.md +46 -0
- package/rules/css/custom-property-pattern.md +45 -0
- package/rules/css/declaration-block-no-duplicate-custom-properties.md +44 -0
- package/rules/css/declaration-block-no-duplicate-properties.cases.md +61 -0
- package/rules/css/declaration-block-no-duplicate-properties.md +44 -0
- package/rules/css/declaration-block-no-redundant-longhand-properties.md +49 -0
- package/rules/css/declaration-block-no-shorthand-property-overrides.md +44 -0
- package/rules/css/declaration-property-value-keyword-no-deprecated.md +40 -0
- package/rules/css/declaration-property-value-no-unknown.cases.md +16 -0
- package/rules/css/declaration-property-value-no-unknown.md +46 -0
- package/rules/css/font-family-no-duplicate-names.cases.md +31 -0
- package/rules/css/font-family-no-duplicate-names.md +37 -0
- package/rules/css/font-family-no-missing-generic-family-keyword.cases.md +62 -0
- package/rules/css/font-family-no-missing-generic-family-keyword.md +44 -0
- package/rules/css/function-calc-no-unspaced-operator.cases.md +33 -0
- package/rules/css/function-calc-no-unspaced-operator.md +42 -0
- package/rules/css/hue-degree-notation.md +41 -0
- package/rules/css/import-notation.md +37 -0
- package/rules/css/keyframe-block-no-duplicate-selectors.md +54 -0
- package/rules/css/keyframe-declaration-no-important.md +50 -0
- package/rules/css/keyframe-selector-notation.md +61 -0
- package/rules/css/keyframes-name-pattern.md +49 -0
- package/rules/css/layer-name-pattern.md +41 -0
- package/rules/css/length-zero-no-unit.cases.md +41 -0
- package/rules/css/length-zero-no-unit.md +39 -0
- package/rules/css/lightness-notation.md +41 -0
- package/rules/css/media-feature-name-no-unknown.md +48 -0
- package/rules/css/media-feature-name-no-vendor-prefix.md +50 -0
- package/rules/css/media-feature-name-value-no-unknown.md +46 -0
- package/rules/css/media-feature-range-notation.cases.md +61 -0
- package/rules/css/media-feature-range-notation.md +45 -0
- package/rules/css/media-query-no-invalid.cases.md +60 -0
- package/rules/css/media-query-no-invalid.md +48 -0
- package/rules/css/media-type-no-deprecated.md +48 -0
- package/rules/css/named-grid-areas-no-invalid.md +47 -0
- package/rules/css/nesting-selector-no-missing-scoping-root.md +44 -0
- package/rules/css/no-descending-specificity.cases.md +69 -0
- package/rules/css/no-descending-specificity.md +57 -0
- package/rules/css/no-duplicate-at-import-rules.md +35 -0
- package/rules/css/no-duplicate-selector.cases.md +67 -0
- package/rules/css/no-duplicate-selector.md +48 -0
- package/rules/css/no-empty-block.cases.md +42 -0
- package/rules/css/no-empty-block.md +42 -0
- package/rules/css/no-empty-source.md +40 -0
- package/rules/css/no-important.md +43 -0
- package/rules/css/no-invalid-double-slash-comments.md +44 -0
- package/rules/css/no-invalid-position-at-import-rule.md +48 -0
- package/rules/css/no-invalid-position-declaration.cases.md +35 -0
- package/rules/css/no-invalid-position-declaration.md +40 -0
- package/rules/css/no-irregular-whitespace.md +38 -0
- package/rules/css/no-unknown-property.cases.md +53 -0
- package/rules/css/no-unknown-property.md +45 -0
- package/rules/css/number-max-precision.md +41 -0
- package/rules/css/property-no-deprecated.md +40 -0
- package/rules/css/property-no-vendor-prefix.md +40 -0
- package/rules/css/selector-anb-no-unmatchable.md +42 -0
- package/rules/css/selector-class-pattern.md +45 -0
- package/rules/css/selector-id-pattern.md +45 -0
- package/rules/css/selector-no-vendor-prefix.md +40 -0
- package/rules/css/selector-not-notation.md +42 -0
- package/rules/css/selector-pseudo-class-no-unknown.cases.md +53 -0
- package/rules/css/selector-pseudo-class-no-unknown.md +44 -0
- package/rules/css/selector-pseudo-element-colon-notation.cases.md +13 -0
- package/rules/css/selector-pseudo-element-colon-notation.md +41 -0
- package/rules/css/selector-pseudo-element-no-unknown.md +44 -0
- package/rules/css/selector-type-no-unknown.cases.md +41 -0
- package/rules/css/selector-type-no-unknown.md +45 -0
- package/rules/css/shorthand-property-no-redundant-values.cases.md +34 -0
- package/rules/css/shorthand-property-no-redundant-values.md +37 -0
- package/rules/css/string-no-newline.cases.md +27 -0
- package/rules/css/string-no-newline.md +45 -0
- package/rules/css/syntax-string-no-invalid.md +46 -0
- package/rules/css/value-no-vendor-prefix.md +40 -0
- package/rules/graph/no-unused-css-classes.md +55 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: css/media-feature-name-value-no-unknown
|
|
3
|
+
title: "Media features have valid values"
|
|
4
|
+
languages: [css]
|
|
5
|
+
fix: manual
|
|
6
|
+
fix_reason: "the intended value is the author's call"
|
|
7
|
+
stability: preview
|
|
8
|
+
ported_from: [stylelint/media-feature-name-value-no-unknown]
|
|
9
|
+
since: 0.1.0
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
A media feature with a fixed set of values (`orientation`, `hover`, `prefers-color-scheme`, …) uses one of them, and a feature with a typed value (`width`, `resolution`, `color`) uses that type.
|
|
13
|
+
|
|
14
|
+
**Why:** A media query with an invalid value never matches, so the block never applies.
|
|
15
|
+
|
|
16
|
+
```codelaw
|
|
17
|
+
native: css/media-feature-name-value-no-unknown
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## How to fix
|
|
21
|
+
|
|
22
|
+
1. Use a value the media feature accepts.
|
|
23
|
+
|
|
24
|
+
## Examples
|
|
25
|
+
|
|
26
|
+
### CSS
|
|
27
|
+
|
|
28
|
+
#### Don't
|
|
29
|
+
|
|
30
|
+
```css
|
|
31
|
+
@media (orientation: sideways) {
|
|
32
|
+
a {
|
|
33
|
+
color: red;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
#### Do
|
|
39
|
+
|
|
40
|
+
```css
|
|
41
|
+
@media (orientation: portrait) {
|
|
42
|
+
a {
|
|
43
|
+
color: red;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
```
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Cases: css/media-feature-range-notation
|
|
2
|
+
|
|
3
|
+
### case: a min- and max- pair becomes two ranges
|
|
4
|
+
|
|
5
|
+
```css
|
|
6
|
+
@media screen and (min-width: 600px) and (max-width: 899.5px) {
|
|
7
|
+
a {
|
|
8
|
+
color: red;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
```expect
|
|
14
|
+
1:19 css/media-feature-range-notation
|
|
15
|
+
1:42 css/media-feature-range-notation
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
```fixed
|
|
19
|
+
@media screen and (width >= 600px) and (width <= 899.5px) {
|
|
20
|
+
a {
|
|
21
|
+
color: red;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### case: every query of a list, and ratios
|
|
27
|
+
|
|
28
|
+
```css
|
|
29
|
+
@media (min-aspect-ratio: 16/9), not (max-resolution: 2dppx) {
|
|
30
|
+
a {
|
|
31
|
+
color: red;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
```expect
|
|
37
|
+
1:8 css/media-feature-range-notation
|
|
38
|
+
1:38 css/media-feature-range-notation
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
```fixed
|
|
42
|
+
@media (aspect-ratio >= 16/9), not (resolution <= 2dppx) {
|
|
43
|
+
a {
|
|
44
|
+
color: red;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### case: range syntax and features without a range are left alone
|
|
50
|
+
|
|
51
|
+
```css
|
|
52
|
+
@media (400px <= width <= 700px) and (hover: hover) and (orientation: landscape) {
|
|
53
|
+
a {
|
|
54
|
+
color: red;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
```expect
|
|
60
|
+
(none)
|
|
61
|
+
```
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: css/media-feature-range-notation
|
|
3
|
+
title: "Range syntax for media features"
|
|
4
|
+
languages: [css]
|
|
5
|
+
fix: auto
|
|
6
|
+
stability: preview
|
|
7
|
+
ported_from: [stylelint/media-feature-range-notation]
|
|
8
|
+
since: 0.1.0
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
Range media features use the comparison syntax, `(width >= 600px)`, not `min-` and `max-` prefixes. The fix rewrites each prefixed feature on its own: `(min-NAME: V)` becomes `(NAME >= V)` and `(max-NAME: V)` becomes `(NAME <= V)`; a `min-` and `max-` pair becomes two ranges, which can be merged by hand into `(V1 <= NAME <= V2)`.
|
|
12
|
+
|
|
13
|
+
**Why:** Comparisons read like the condition they express, and can state exclusive bounds.
|
|
14
|
+
|
|
15
|
+
```codelaw
|
|
16
|
+
native: css/media-feature-range-notation
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Examples
|
|
20
|
+
|
|
21
|
+
### CSS
|
|
22
|
+
|
|
23
|
+
#### Don't
|
|
24
|
+
|
|
25
|
+
```css
|
|
26
|
+
@media (min-width: 600px) {
|
|
27
|
+
a {
|
|
28
|
+
color: red;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
#### Do
|
|
34
|
+
|
|
35
|
+
```css
|
|
36
|
+
@media (width >= 600px) {
|
|
37
|
+
a {
|
|
38
|
+
color: red;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Differences from the source
|
|
44
|
+
|
|
45
|
+
Ported with stylelint-config-standard's setting, `context`. The fix does not merge a `min-` and `max-` pair into one range.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Cases: css/media-query-no-invalid
|
|
2
|
+
|
|
3
|
+
### case: level 4 ranges and nesting
|
|
4
|
+
|
|
5
|
+
```css
|
|
6
|
+
@media (400px <= width <= 700px) and ((hover) or (pointer: fine)) {
|
|
7
|
+
a {
|
|
8
|
+
color: red;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
```expect
|
|
14
|
+
(none)
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### case: mixed and/or
|
|
18
|
+
|
|
19
|
+
```css
|
|
20
|
+
@media (color) and (hover) or (width) {
|
|
21
|
+
a {
|
|
22
|
+
color: red;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
```expect
|
|
28
|
+
1:8 css/media-query-no-invalid
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### case: a media type with not
|
|
32
|
+
|
|
33
|
+
```css
|
|
34
|
+
@media not print and (color) {
|
|
35
|
+
a {
|
|
36
|
+
color: red;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
```expect
|
|
42
|
+
(none)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### case: not without a space
|
|
46
|
+
|
|
47
|
+
`not(` is a function token, not the keyword. `codelaw format` writes `not (`, which turns this
|
|
48
|
+
query valid; the finding comes first because lint runs before format (SR-FORMATTER decision 4).
|
|
49
|
+
|
|
50
|
+
```css
|
|
51
|
+
@media not(min-width: 600px) {
|
|
52
|
+
a {
|
|
53
|
+
color: red;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
```expect
|
|
59
|
+
1:8 css/media-query-no-invalid
|
|
60
|
+
```
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: css/media-query-no-invalid
|
|
3
|
+
title: "Media queries follow the grammar"
|
|
4
|
+
languages: [css]
|
|
5
|
+
fix: manual
|
|
6
|
+
fix_reason: "the intended query is the author's call"
|
|
7
|
+
stability: preview
|
|
8
|
+
options:
|
|
9
|
+
ignoreFunctions: { type: "string[]", default: [], description: "functions to accept in queries, such as `theme`" }
|
|
10
|
+
ported_from: [stylelint/media-query-no-invalid]
|
|
11
|
+
since: 0.1.0
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
Every query in `@media` and `@custom-media` is grammatical under Media Queries level 5: `not` is followed by a space, comparisons are `<`, `<=`, `>`, `>=` or `=`, and `and` and `or` are not mixed without parentheses.
|
|
15
|
+
|
|
16
|
+
**Why:** A browser treats an invalid query as `not all`, so the block never applies.
|
|
17
|
+
|
|
18
|
+
```codelaw
|
|
19
|
+
native: css/media-query-no-invalid
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## How to fix
|
|
23
|
+
|
|
24
|
+
1. Rewrite the query; add parentheses to group `and` and `or`, and a space after `not`.
|
|
25
|
+
|
|
26
|
+
## Examples
|
|
27
|
+
|
|
28
|
+
### CSS
|
|
29
|
+
|
|
30
|
+
#### Don't
|
|
31
|
+
|
|
32
|
+
```css
|
|
33
|
+
@media (color) and (hover) or (width >= 600px) {
|
|
34
|
+
a {
|
|
35
|
+
color: red;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
#### Do
|
|
41
|
+
|
|
42
|
+
```css
|
|
43
|
+
@media (color) and ((hover) or (width >= 600px)) {
|
|
44
|
+
a {
|
|
45
|
+
color: red;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
```
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: css/media-type-no-deprecated
|
|
3
|
+
title: "No deprecated media types"
|
|
4
|
+
languages: [css]
|
|
5
|
+
fix: manual
|
|
6
|
+
fix_reason: "the media features that describe the device are the author's call"
|
|
7
|
+
stability: preview
|
|
8
|
+
options:
|
|
9
|
+
ignoreMediaTypes: { type: "string[]", default: [], description: "media types to accept" }
|
|
10
|
+
ported_from: [stylelint/media-type-no-deprecated]
|
|
11
|
+
since: 0.1.0
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
Media queries use no media type the specifications deprecated: `tv`, `handheld`, `projection`, `aural`, `braille`, `embossed`, `speech` and `tty`.
|
|
15
|
+
|
|
16
|
+
**Why:** Deprecated media types match nothing, so the block never applies.
|
|
17
|
+
|
|
18
|
+
```codelaw
|
|
19
|
+
native: css/media-type-no-deprecated
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## How to fix
|
|
23
|
+
|
|
24
|
+
1. Replace the media type with `screen`, `print` or `all`, adding media features that describe the device.
|
|
25
|
+
|
|
26
|
+
## Examples
|
|
27
|
+
|
|
28
|
+
### CSS
|
|
29
|
+
|
|
30
|
+
#### Don't
|
|
31
|
+
|
|
32
|
+
```css
|
|
33
|
+
@media tv {
|
|
34
|
+
a {
|
|
35
|
+
color: red;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
#### Do
|
|
41
|
+
|
|
42
|
+
```css
|
|
43
|
+
@media screen {
|
|
44
|
+
a {
|
|
45
|
+
color: red;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
```
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: css/named-grid-areas-no-invalid
|
|
3
|
+
title: "Named grid areas are rectangles"
|
|
4
|
+
languages: [css]
|
|
5
|
+
fix: manual
|
|
6
|
+
fix_reason: "the intended layout is the author's call"
|
|
7
|
+
stability: preview
|
|
8
|
+
ported_from: [stylelint/named-grid-areas-no-invalid]
|
|
9
|
+
since: 0.1.0
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
In `grid-template-areas` (and `grid-template`, `grid`), every row string has at least one cell, every row has the same number of cells, and each named area forms one filled-in rectangle.
|
|
13
|
+
|
|
14
|
+
**Why:** The browser drops an invalid `grid-template-areas` declaration, and the grid loses all its named areas.
|
|
15
|
+
|
|
16
|
+
```codelaw
|
|
17
|
+
native: css/named-grid-areas-no-invalid
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## How to fix
|
|
21
|
+
|
|
22
|
+
1. Give every row the same number of cells.
|
|
23
|
+
2. Make each name cover a rectangle of cells.
|
|
24
|
+
|
|
25
|
+
## Examples
|
|
26
|
+
|
|
27
|
+
### CSS
|
|
28
|
+
|
|
29
|
+
#### Don't
|
|
30
|
+
|
|
31
|
+
```css
|
|
32
|
+
a {
|
|
33
|
+
grid-template-areas:
|
|
34
|
+
"head head"
|
|
35
|
+
"side main main";
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
#### Do
|
|
40
|
+
|
|
41
|
+
```css
|
|
42
|
+
a {
|
|
43
|
+
grid-template-areas:
|
|
44
|
+
"head head head"
|
|
45
|
+
"side main main";
|
|
46
|
+
}
|
|
47
|
+
```
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: css/nesting-selector-no-missing-scoping-root
|
|
3
|
+
title: "Nesting selectors have a parent"
|
|
4
|
+
languages: [css]
|
|
5
|
+
fix: manual
|
|
6
|
+
fix_reason: "the intended parent selector is the author's call"
|
|
7
|
+
stability: preview
|
|
8
|
+
ported_from: [stylelint/nesting-selector-no-missing-scoping-root]
|
|
9
|
+
since: 0.1.0
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
The nesting selector `&` is used only inside a style rule (or under `@scope`), where it stands for the parent selector.
|
|
13
|
+
|
|
14
|
+
**Why:** At the top level `&` matches the root element, which is almost never what was meant.
|
|
15
|
+
|
|
16
|
+
```codelaw
|
|
17
|
+
native: css/nesting-selector-no-missing-scoping-root
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## How to fix
|
|
21
|
+
|
|
22
|
+
1. Nest the rule inside the rule `&` should refer to, or replace `&` with that selector.
|
|
23
|
+
|
|
24
|
+
## Examples
|
|
25
|
+
|
|
26
|
+
### CSS
|
|
27
|
+
|
|
28
|
+
#### Don't
|
|
29
|
+
|
|
30
|
+
```css
|
|
31
|
+
& .item {
|
|
32
|
+
color: red;
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
#### Do
|
|
37
|
+
|
|
38
|
+
```css
|
|
39
|
+
.list {
|
|
40
|
+
& .item {
|
|
41
|
+
color: red;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
```
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Cases: css/no-descending-specificity
|
|
2
|
+
|
|
3
|
+
### case: different media contexts are not compared
|
|
4
|
+
|
|
5
|
+
```css
|
|
6
|
+
#nav a {
|
|
7
|
+
color: red;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
@media print {
|
|
11
|
+
a {
|
|
12
|
+
color: black;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
```expect
|
|
18
|
+
(none)
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### case: pseudo-elements are compared only with themselves
|
|
22
|
+
|
|
23
|
+
```css
|
|
24
|
+
a::before {
|
|
25
|
+
content: "";
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
a {
|
|
29
|
+
color: red;
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
```expect
|
|
34
|
+
(none)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### case: pseudo-classes are ignored when comparing
|
|
38
|
+
|
|
39
|
+
```css
|
|
40
|
+
a:hover {
|
|
41
|
+
color: red;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
a {
|
|
45
|
+
color: blue;
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
```expect
|
|
50
|
+
5:1 css/no-descending-specificity
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### case: nested selectors are resolved
|
|
54
|
+
|
|
55
|
+
```css
|
|
56
|
+
#nav {
|
|
57
|
+
a {
|
|
58
|
+
color: red;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
a {
|
|
63
|
+
color: blue;
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
```expect
|
|
68
|
+
7:1 css/no-descending-specificity
|
|
69
|
+
```
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: css/no-descending-specificity
|
|
3
|
+
title: "Less specific selectors come first"
|
|
4
|
+
languages: [css]
|
|
5
|
+
fix: manual
|
|
6
|
+
fix_reason: "reordering rules can change which declarations win"
|
|
7
|
+
stability: preview
|
|
8
|
+
options:
|
|
9
|
+
ignore: { type: "string[]", default: [], description: "`selectors-within-list` skips rules with a selector list" }
|
|
10
|
+
ported_from: [stylelint/no-descending-specificity]
|
|
11
|
+
since: 0.1.0
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
A selector does not come after a more specific selector that targets the same element (the same last compound selector, pseudo-classes aside), within the same at-rule.
|
|
15
|
+
|
|
16
|
+
**Why:** The earlier, more specific rule wins whatever the order, so reading the sheet top to bottom misleads.
|
|
17
|
+
|
|
18
|
+
```codelaw
|
|
19
|
+
native: css/no-descending-specificity
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## How to fix
|
|
23
|
+
|
|
24
|
+
1. Move the less specific rule above the more specific one.
|
|
25
|
+
2. Check that the page still renders the same.
|
|
26
|
+
|
|
27
|
+
## Examples
|
|
28
|
+
|
|
29
|
+
### CSS
|
|
30
|
+
|
|
31
|
+
#### Don't
|
|
32
|
+
|
|
33
|
+
```css
|
|
34
|
+
#nav a {
|
|
35
|
+
color: red;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
a {
|
|
39
|
+
color: blue;
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
#### Do
|
|
44
|
+
|
|
45
|
+
```css
|
|
46
|
+
a {
|
|
47
|
+
color: blue;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
#nav a {
|
|
51
|
+
color: red;
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Differences from the source
|
|
56
|
+
|
|
57
|
+
A nested selector's `&` is resolved against each parent selector separately; stylelint uses the highest specificity among them, as `:is()` would.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: css/no-duplicate-at-import-rules
|
|
3
|
+
title: "No stylesheet imported twice"
|
|
4
|
+
languages: [css]
|
|
5
|
+
fix: suggest
|
|
6
|
+
fix_reason: "removing the later import moves its rules earlier in the cascade"
|
|
7
|
+
stability: preview
|
|
8
|
+
ported_from: [stylelint/no-duplicate-at-import-rules]
|
|
9
|
+
since: 0.1.0
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
Each stylesheet is imported once with the same media conditions.
|
|
13
|
+
|
|
14
|
+
**Why:** The second import loads the same rules again, which costs a request and can reorder the cascade.
|
|
15
|
+
|
|
16
|
+
```codelaw
|
|
17
|
+
native: css/no-duplicate-at-import-rules
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Examples
|
|
21
|
+
|
|
22
|
+
### CSS
|
|
23
|
+
|
|
24
|
+
#### Don't
|
|
25
|
+
|
|
26
|
+
```css
|
|
27
|
+
@import url("base.css");
|
|
28
|
+
@import url("base.css");
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
#### Do
|
|
32
|
+
|
|
33
|
+
```css
|
|
34
|
+
@import url("base.css");
|
|
35
|
+
```
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Cases: css/no-duplicate-selector
|
|
2
|
+
|
|
3
|
+
### case: different at-rule contexts
|
|
4
|
+
|
|
5
|
+
```css
|
|
6
|
+
a {
|
|
7
|
+
color: red;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
@media print {
|
|
11
|
+
a {
|
|
12
|
+
color: black;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
```expect
|
|
18
|
+
(none)
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### case: the same list in another order
|
|
22
|
+
|
|
23
|
+
```css
|
|
24
|
+
a, b {
|
|
25
|
+
color: red;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
b, a {
|
|
29
|
+
margin: 0;
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
```expect
|
|
34
|
+
5:1 css/no-duplicate-selector
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### case: one selector twice in a list
|
|
38
|
+
|
|
39
|
+
```css
|
|
40
|
+
a, b, a {
|
|
41
|
+
color: red;
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
```expect
|
|
46
|
+
1:7 css/no-duplicate-selector
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### case: keyframe selectors are not style rules
|
|
50
|
+
|
|
51
|
+
```css
|
|
52
|
+
@keyframes a {
|
|
53
|
+
0% {
|
|
54
|
+
top: 0;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
@keyframes b {
|
|
59
|
+
0% {
|
|
60
|
+
top: 1px;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
```expect
|
|
66
|
+
(none)
|
|
67
|
+
```
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: css/no-duplicate-selector
|
|
3
|
+
title: "No selector declared twice"
|
|
4
|
+
languages: [css]
|
|
5
|
+
fix: manual
|
|
6
|
+
fix_reason: "merging the rules depends on cascade order"
|
|
7
|
+
stability: preview
|
|
8
|
+
ported_from: [stylelint/no-duplicate-selectors]
|
|
9
|
+
since: 0.1.0
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
Two rules in the same at-rule context do not have the same selector list (order and whitespace aside, nesting resolved), and one selector list does not name a selector twice.
|
|
13
|
+
|
|
14
|
+
**Why:** Split declarations for one selector are hard to follow and often contradict each other.
|
|
15
|
+
|
|
16
|
+
```codelaw
|
|
17
|
+
native: css/no-duplicate-selector
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## How to fix
|
|
21
|
+
|
|
22
|
+
1. Merge the declarations of both rules into the first.
|
|
23
|
+
2. Check that rules between them did not depend on the order.
|
|
24
|
+
|
|
25
|
+
## Examples
|
|
26
|
+
|
|
27
|
+
### CSS
|
|
28
|
+
|
|
29
|
+
#### Don't
|
|
30
|
+
|
|
31
|
+
```css
|
|
32
|
+
.card {
|
|
33
|
+
color: red;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.card {
|
|
37
|
+
margin: 0;
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
#### Do
|
|
42
|
+
|
|
43
|
+
```css
|
|
44
|
+
.card {
|
|
45
|
+
color: red;
|
|
46
|
+
margin: 0;
|
|
47
|
+
}
|
|
48
|
+
```
|