@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.
Files changed (116) hide show
  1. package/LICENSE +23 -0
  2. package/NOTICE +45 -0
  3. package/README.md +181 -2
  4. package/codelaw-pack.toml +6 -0
  5. package/data/css/at-rules.json +97 -0
  6. package/data/css/deprecated.json +178 -0
  7. package/data/css/descriptors.json +121 -0
  8. package/data/css/functions.json +49 -0
  9. package/data/css/keywords.json +332 -0
  10. package/data/css/media.json +271 -0
  11. package/data/css/prefixed.json +266 -0
  12. package/data/css/properties-groups.json +183 -0
  13. package/data/css/properties.json +1326 -0
  14. package/data/css/property-keywords.json +394 -0
  15. package/data/css/selectors.json +281 -0
  16. package/data/css/shorthands.json +351 -0
  17. package/data/css/type-selectors.json +447 -0
  18. package/data/css/units.json +123 -0
  19. package/package.json +14 -4
  20. package/presets/css/conventions.toml +4 -0
  21. package/presets/css/recommended.toml +44 -0
  22. package/presets/css/standard.toml +31 -0
  23. package/rules/css/alpha-value-notation.cases.md +37 -0
  24. package/rules/css/alpha-value-notation.md +44 -0
  25. package/rules/css/annotation-no-unknown.md +44 -0
  26. package/rules/css/at-rule-descriptor-no-unknown.md +46 -0
  27. package/rules/css/at-rule-descriptor-value-no-unknown.md +50 -0
  28. package/rules/css/at-rule-no-deprecated.cases.md +13 -0
  29. package/rules/css/at-rule-no-deprecated.md +47 -0
  30. package/rules/css/at-rule-no-unknown.cases.md +25 -0
  31. package/rules/css/at-rule-no-unknown.md +49 -0
  32. package/rules/css/at-rule-no-vendor-prefix.md +44 -0
  33. package/rules/css/at-rule-prelude-no-invalid.md +52 -0
  34. package/rules/css/block-no-redundant-nested-style-rules.md +40 -0
  35. package/rules/css/color-function-alias-notation.md +42 -0
  36. package/rules/css/color-function-notation.md +42 -0
  37. package/rules/css/color-hex-length.cases.md +13 -0
  38. package/rules/css/color-hex-length.md +41 -0
  39. package/rules/css/comment-no-empty.md +38 -0
  40. package/rules/css/container-name-pattern.md +45 -0
  41. package/rules/css/custom-media-pattern.md +41 -0
  42. package/rules/css/custom-property-no-missing-var-function.cases.md +61 -0
  43. package/rules/css/custom-property-no-missing-var-function.md +46 -0
  44. package/rules/css/custom-property-pattern.md +45 -0
  45. package/rules/css/declaration-block-no-duplicate-custom-properties.md +44 -0
  46. package/rules/css/declaration-block-no-duplicate-properties.cases.md +61 -0
  47. package/rules/css/declaration-block-no-duplicate-properties.md +44 -0
  48. package/rules/css/declaration-block-no-redundant-longhand-properties.md +49 -0
  49. package/rules/css/declaration-block-no-shorthand-property-overrides.md +44 -0
  50. package/rules/css/declaration-property-value-keyword-no-deprecated.md +40 -0
  51. package/rules/css/declaration-property-value-no-unknown.cases.md +16 -0
  52. package/rules/css/declaration-property-value-no-unknown.md +46 -0
  53. package/rules/css/font-family-no-duplicate-names.cases.md +31 -0
  54. package/rules/css/font-family-no-duplicate-names.md +37 -0
  55. package/rules/css/font-family-no-missing-generic-family-keyword.cases.md +62 -0
  56. package/rules/css/font-family-no-missing-generic-family-keyword.md +44 -0
  57. package/rules/css/function-calc-no-unspaced-operator.cases.md +33 -0
  58. package/rules/css/function-calc-no-unspaced-operator.md +42 -0
  59. package/rules/css/hue-degree-notation.md +41 -0
  60. package/rules/css/import-notation.md +37 -0
  61. package/rules/css/keyframe-block-no-duplicate-selectors.md +54 -0
  62. package/rules/css/keyframe-declaration-no-important.md +50 -0
  63. package/rules/css/keyframe-selector-notation.md +61 -0
  64. package/rules/css/keyframes-name-pattern.md +49 -0
  65. package/rules/css/layer-name-pattern.md +41 -0
  66. package/rules/css/length-zero-no-unit.cases.md +41 -0
  67. package/rules/css/length-zero-no-unit.md +39 -0
  68. package/rules/css/lightness-notation.md +41 -0
  69. package/rules/css/media-feature-name-no-unknown.md +48 -0
  70. package/rules/css/media-feature-name-no-vendor-prefix.md +50 -0
  71. package/rules/css/media-feature-name-value-no-unknown.md +46 -0
  72. package/rules/css/media-feature-range-notation.cases.md +61 -0
  73. package/rules/css/media-feature-range-notation.md +45 -0
  74. package/rules/css/media-query-no-invalid.cases.md +60 -0
  75. package/rules/css/media-query-no-invalid.md +48 -0
  76. package/rules/css/media-type-no-deprecated.md +48 -0
  77. package/rules/css/named-grid-areas-no-invalid.md +47 -0
  78. package/rules/css/nesting-selector-no-missing-scoping-root.md +44 -0
  79. package/rules/css/no-descending-specificity.cases.md +69 -0
  80. package/rules/css/no-descending-specificity.md +57 -0
  81. package/rules/css/no-duplicate-at-import-rules.md +35 -0
  82. package/rules/css/no-duplicate-selector.cases.md +67 -0
  83. package/rules/css/no-duplicate-selector.md +48 -0
  84. package/rules/css/no-empty-block.cases.md +42 -0
  85. package/rules/css/no-empty-block.md +42 -0
  86. package/rules/css/no-empty-source.md +40 -0
  87. package/rules/css/no-important.md +43 -0
  88. package/rules/css/no-invalid-double-slash-comments.md +44 -0
  89. package/rules/css/no-invalid-position-at-import-rule.md +48 -0
  90. package/rules/css/no-invalid-position-declaration.cases.md +35 -0
  91. package/rules/css/no-invalid-position-declaration.md +40 -0
  92. package/rules/css/no-irregular-whitespace.md +38 -0
  93. package/rules/css/no-unknown-property.cases.md +53 -0
  94. package/rules/css/no-unknown-property.md +45 -0
  95. package/rules/css/number-max-precision.md +41 -0
  96. package/rules/css/property-no-deprecated.md +40 -0
  97. package/rules/css/property-no-vendor-prefix.md +40 -0
  98. package/rules/css/selector-anb-no-unmatchable.md +42 -0
  99. package/rules/css/selector-class-pattern.md +45 -0
  100. package/rules/css/selector-id-pattern.md +45 -0
  101. package/rules/css/selector-no-vendor-prefix.md +40 -0
  102. package/rules/css/selector-not-notation.md +42 -0
  103. package/rules/css/selector-pseudo-class-no-unknown.cases.md +53 -0
  104. package/rules/css/selector-pseudo-class-no-unknown.md +44 -0
  105. package/rules/css/selector-pseudo-element-colon-notation.cases.md +13 -0
  106. package/rules/css/selector-pseudo-element-colon-notation.md +41 -0
  107. package/rules/css/selector-pseudo-element-no-unknown.md +44 -0
  108. package/rules/css/selector-type-no-unknown.cases.md +41 -0
  109. package/rules/css/selector-type-no-unknown.md +45 -0
  110. package/rules/css/shorthand-property-no-redundant-values.cases.md +34 -0
  111. package/rules/css/shorthand-property-no-redundant-values.md +37 -0
  112. package/rules/css/string-no-newline.cases.md +27 -0
  113. package/rules/css/string-no-newline.md +45 -0
  114. package/rules/css/syntax-string-no-invalid.md +46 -0
  115. package/rules/css/value-no-vendor-prefix.md +40 -0
  116. 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
+ ```