@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,41 @@
1
+ ---
2
+ id: css/custom-media-pattern
3
+ title: "Custom media names are kebab-case"
4
+ languages: [css]
5
+ fix: manual
6
+ fix_reason: "renaming must update every use of the name"
7
+ stability: preview
8
+ options:
9
+ pattern: { type: "string", default: "^([a-z][a-z0-9]*)(-[a-z0-9]+)*$", description: "a regular expression names must match (without the leading `--`)" }
10
+ ported_from: [stylelint/custom-media-pattern]
11
+ since: 0.1.0
12
+ ---
13
+
14
+ The name of each `@custom-media` (after `--`) matches a pattern, kebab-case by default.
15
+
16
+ **Why:** A consistent naming scheme makes names predictable across a codebase.
17
+
18
+ ```codelaw
19
+ native: css/custom-media-pattern
20
+ ```
21
+
22
+ ## How to fix
23
+
24
+ 1. Rename the custom media to match the pattern.
25
+ 2. Update every query that uses it.
26
+
27
+ ## Examples
28
+
29
+ ### CSS
30
+
31
+ #### Don't
32
+
33
+ ```css
34
+ @custom-media --smallViewport (width <= 30em);
35
+ ```
36
+
37
+ #### Do
38
+
39
+ ```css
40
+ @custom-media --small-viewport (width <= 30em);
41
+ ```
@@ -0,0 +1,61 @@
1
+ # Cases: css/custom-property-no-missing-var-function
2
+
3
+ ### case: properties that take names
4
+
5
+ ```css
6
+ :root {
7
+ --fade: 1;
8
+ }
9
+
10
+ a {
11
+ transition-property: --fade;
12
+ }
13
+ ```
14
+
15
+ ```expect
16
+ (none)
17
+ ```
18
+
19
+ ### case: arguments of a custom function
20
+
21
+ ```css
22
+ :root {
23
+ --base: 1rem;
24
+ }
25
+
26
+ a {
27
+ margin: --theme(--base);
28
+ }
29
+ ```
30
+
31
+ ```expect
32
+ (none)
33
+ ```
34
+
35
+ ### case: a bare name in a var() fallback
36
+
37
+ ```css
38
+ :root {
39
+ --b: 1px;
40
+ }
41
+
42
+ a {
43
+ margin: var(--a, --b);
44
+ }
45
+ ```
46
+
47
+ ```expect
48
+ 6:20 css/custom-property-no-missing-var-function
49
+ ```
50
+
51
+ ### case: an undefined name is not checked
52
+
53
+ ```css
54
+ a {
55
+ color: --brand;
56
+ }
57
+ ```
58
+
59
+ ```expect
60
+ (none)
61
+ ```
@@ -0,0 +1,46 @@
1
+ ---
2
+ id: css/custom-property-no-missing-var-function
3
+ title: "Custom properties are read with `var()`"
4
+ languages: [css]
5
+ fix: suggest
6
+ fix_reason: "wrapping in `var()` makes a dropped declaration apply, which changes the page"
7
+ stability: preview
8
+ ported_from: [stylelint/custom-property-no-missing-var-function]
9
+ since: 0.1.0
10
+ ---
11
+
12
+ A value names a custom property defined in the same sheet only inside `var()`.
13
+
14
+ **Why:** Without `var()` the value is the identifier `--name`, which is invalid for most properties, so the declaration is dropped.
15
+
16
+ ```codelaw
17
+ native: css/custom-property-no-missing-var-function
18
+ ```
19
+
20
+ ## Examples
21
+
22
+ ### CSS
23
+
24
+ #### Don't
25
+
26
+ ```css
27
+ :root {
28
+ --brand: red;
29
+ }
30
+
31
+ a {
32
+ color: --brand;
33
+ }
34
+ ```
35
+
36
+ #### Do
37
+
38
+ ```css
39
+ :root {
40
+ --brand: red;
41
+ }
42
+
43
+ a {
44
+ color: var(--brand);
45
+ }
46
+ ```
@@ -0,0 +1,45 @@
1
+ ---
2
+ id: css/custom-property-pattern
3
+ title: "Custom property names are kebab-case"
4
+ languages: [css]
5
+ fix: manual
6
+ fix_reason: "renaming must update every use of the name, also in scripts"
7
+ stability: preview
8
+ options:
9
+ pattern: { type: "string", default: "^([a-z][a-z0-9]*)(-[a-z0-9]+)*$", description: "a regular expression names must match (without the leading `--`)" }
10
+ ported_from: [stylelint/custom-property-pattern]
11
+ since: 0.1.0
12
+ ---
13
+
14
+ Custom property names (after `--`), in declarations, `var()` and `@property`, match a pattern, kebab-case by default.
15
+
16
+ **Why:** A consistent naming scheme makes names predictable across a codebase.
17
+
18
+ ```codelaw
19
+ native: css/custom-property-pattern
20
+ ```
21
+
22
+ ## How to fix
23
+
24
+ 1. Rename the custom property to match the pattern.
25
+ 2. Update every `var()` and script that reads it.
26
+
27
+ ## Examples
28
+
29
+ ### CSS
30
+
31
+ #### Don't
32
+
33
+ ```css
34
+ :root {
35
+ --brandColor: red;
36
+ }
37
+ ```
38
+
39
+ #### Do
40
+
41
+ ```css
42
+ :root {
43
+ --brand-color: red;
44
+ }
45
+ ```
@@ -0,0 +1,44 @@
1
+ ---
2
+ id: css/declaration-block-no-duplicate-custom-properties
3
+ title: "No custom property declared twice in one block"
4
+ languages: [css]
5
+ fix: manual
6
+ fix_reason: "which value should win can't be known from the code"
7
+ stability: preview
8
+ ported_from: [stylelint/declaration-block-no-duplicate-custom-properties]
9
+ since: 0.1.0
10
+ ---
11
+
12
+ A declaration block declares each custom property once.
13
+
14
+ **Why:** Only the last declaration counts, so the earlier one is dead code or a mistake.
15
+
16
+ ```codelaw
17
+ native: css/declaration-block-no-duplicate-custom-properties
18
+ ```
19
+
20
+ ## How to fix
21
+
22
+ 1. Decide which value the custom property should have.
23
+ 2. Remove the other declaration.
24
+
25
+ ## Examples
26
+
27
+ ### CSS
28
+
29
+ #### Don't
30
+
31
+ ```css
32
+ a {
33
+ --gap: 4px;
34
+ --gap: 8px;
35
+ }
36
+ ```
37
+
38
+ #### Do
39
+
40
+ ```css
41
+ a {
42
+ --gap: 8px;
43
+ }
44
+ ```
@@ -0,0 +1,61 @@
1
+ # Cases: css/declaration-block-no-duplicate-properties
2
+
3
+ ### case: a fallback with a different syntax is allowed
4
+
5
+ ```css
6
+ a {
7
+ width: 100px;
8
+ width: 50vw;
9
+ }
10
+ ```
11
+
12
+ ```expect
13
+ (none)
14
+ ```
15
+
16
+ ### case: the same syntax twice in a row is reported
17
+
18
+ ```css
19
+ a {
20
+ font-size: 16px;
21
+ font-size: 14px;
22
+ }
23
+ ```
24
+
25
+ ```expect
26
+ 2:3 css/declaration-block-no-duplicate-properties
27
+ ```
28
+
29
+ ```fixed
30
+ a {
31
+ font-size: 14px;
32
+ }
33
+ ```
34
+
35
+ ### case: `src` repeats in @font-face
36
+
37
+ ```css
38
+ @font-face {
39
+ font-family: "Inter";
40
+ src: url("a.eot");
41
+ src: url("a.woff2") format("woff2");
42
+ }
43
+ ```
44
+
45
+ ```expect
46
+ (none)
47
+ ```
48
+
49
+ ### case: an earlier !important wins
50
+
51
+ ```css
52
+ a {
53
+ color: red !important;
54
+ background: none;
55
+ color: blue;
56
+ }
57
+ ```
58
+
59
+ ```expect
60
+ 4:3 css/declaration-block-no-duplicate-properties
61
+ ```
@@ -0,0 +1,44 @@
1
+ ---
2
+ id: css/declaration-block-no-duplicate-properties
3
+ title: "No property declared twice in one block"
4
+ languages: [css]
5
+ fix: suggest
6
+ fix_reason: "the earlier declaration may be a deliberate fallback for browsers that reject the later value"
7
+ stability: preview
8
+ options:
9
+ ignore: { type: "string[]", default: ["consecutive-duplicates-with-different-syntaxes"], description: "`consecutive-duplicates-with-different-syntaxes` allows fallbacks" }
10
+ ignoreProperties: { type: "string[]", default: [], description: "properties to skip; `/regex/` for a pattern" }
11
+ ported_from: [stylelint/declaration-block-no-duplicate-properties]
12
+ since: 0.1.0
13
+ ---
14
+
15
+ A declaration block declares each property once. Back-to-back declarations whose values have different syntaxes — a fallback such as `width: 100px; width: 50vw;` — are allowed, and so is `src`.
16
+
17
+ **Why:** The later declaration overrides the earlier one, so the earlier one is dead code or a mistake.
18
+
19
+ ```codelaw
20
+ native: css/declaration-block-no-duplicate-properties
21
+ ```
22
+
23
+ ## Examples
24
+
25
+ ### CSS
26
+
27
+ #### Don't
28
+
29
+ ```css
30
+ a {
31
+ color: pink;
32
+ background: orange;
33
+ color: orange;
34
+ }
35
+ ```
36
+
37
+ #### Do
38
+
39
+ ```css
40
+ a {
41
+ background: orange;
42
+ color: orange;
43
+ }
44
+ ```
@@ -0,0 +1,49 @@
1
+ ---
2
+ id: css/declaration-block-no-redundant-longhand-properties
3
+ title: "Shorthands instead of complete sets of longhands"
4
+ languages: [css]
5
+ fix: manual
6
+ fix_reason: "combining longhands into a shorthand value needs the shorthand's grammar"
7
+ stability: preview
8
+ ported_from: [stylelint/declaration-block-no-redundant-longhand-properties]
9
+ since: 0.1.0
10
+ ---
11
+
12
+ A block does not declare every longhand of a shorthand (`margin-top`, `margin-right`, `margin-bottom`, `margin-left`) where the shorthand would do, nor repeat a shorthand's value in one of its longhands.
13
+
14
+ **Why:** One shorthand is shorter and says plainly that every side is set.
15
+
16
+ ```codelaw
17
+ native: css/declaration-block-no-redundant-longhand-properties
18
+ ```
19
+
20
+ ## How to fix
21
+
22
+ 1. Replace the longhands with the shorthand, giving their values in the shorthand's order.
23
+
24
+ ## Examples
25
+
26
+ ### CSS
27
+
28
+ #### Don't
29
+
30
+ ```css
31
+ a {
32
+ margin-top: 1px;
33
+ margin-right: 2px;
34
+ margin-bottom: 3px;
35
+ margin-left: 4px;
36
+ }
37
+ ```
38
+
39
+ #### Do
40
+
41
+ ```css
42
+ a {
43
+ margin: 1px 2px 3px 4px;
44
+ }
45
+ ```
46
+
47
+ ## Differences from the source
48
+
49
+ Reported without a fix; stylelint rewrites some sets into the shorthand.
@@ -0,0 +1,44 @@
1
+ ---
2
+ id: css/declaration-block-no-shorthand-property-overrides
3
+ title: "No shorthand after a longhand it resets"
4
+ languages: [css]
5
+ fix: manual
6
+ fix_reason: "which value is meant can't be known from the code"
7
+ stability: preview
8
+ ported_from: [stylelint/declaration-block-no-shorthand-property-overrides]
9
+ since: 0.1.0
10
+ ---
11
+
12
+ A shorthand property does not follow, in the same block, a longhand it covers.
13
+
14
+ **Why:** The shorthand resets the longhand declared before it, so the longhand never applies.
15
+
16
+ ```codelaw
17
+ native: css/declaration-block-no-shorthand-property-overrides
18
+ ```
19
+
20
+ ## How to fix
21
+
22
+ 1. Move the longhand after the shorthand, or fold its value into the shorthand.
23
+
24
+ ## Examples
25
+
26
+ ### CSS
27
+
28
+ #### Don't
29
+
30
+ ```css
31
+ a {
32
+ padding-left: 10px;
33
+ padding: 20px;
34
+ }
35
+ ```
36
+
37
+ #### Do
38
+
39
+ ```css
40
+ a {
41
+ padding: 20px;
42
+ padding-left: 10px;
43
+ }
44
+ ```
@@ -0,0 +1,40 @@
1
+ ---
2
+ id: css/declaration-property-value-keyword-no-deprecated
3
+ title: "No deprecated keywords in property values"
4
+ languages: [css]
5
+ fix: suggest
6
+ fix_reason: "the replacement keyword is the closest modern one, not always identical"
7
+ stability: preview
8
+ options:
9
+ ignoreKeywords: { type: "string[]", default: [], description: "keywords to accept; `/regex/` for a pattern" }
10
+ ported_from: [stylelint/declaration-property-value-keyword-no-deprecated]
11
+ since: 0.1.0
12
+ ---
13
+
14
+ Values use no keyword the specifications deprecated, such as `overflow: overlay`, `word-break: break-word` or the old system colours (`ThreeDFace`).
15
+
16
+ **Why:** Deprecated keywords are aliased or dropped by browsers and may stop working.
17
+
18
+ ```codelaw
19
+ native: css/declaration-property-value-keyword-no-deprecated
20
+ ```
21
+
22
+ ## Examples
23
+
24
+ ### CSS
25
+
26
+ #### Don't
27
+
28
+ ```css
29
+ a {
30
+ overflow: overlay;
31
+ }
32
+ ```
33
+
34
+ #### Do
35
+
36
+ ```css
37
+ a {
38
+ overflow: auto;
39
+ }
40
+ ```
@@ -0,0 +1,16 @@
1
+ # Cases: css/declaration-property-value-no-unknown
2
+
3
+ ### case: CSS-wide keywords, prefixes and variables
4
+
5
+ ```css
6
+ a {
7
+ position: inherit;
8
+ position: -webkit-sticky;
9
+ position: var(--pos);
10
+ float: inline-start;
11
+ }
12
+ ```
13
+
14
+ ```expect
15
+ (none)
16
+ ```
@@ -0,0 +1,46 @@
1
+ ---
2
+ id: css/declaration-property-value-no-unknown
3
+ title: "Keyword-valued properties use a known keyword"
4
+ languages: [css]
5
+ fix: manual
6
+ fix_reason: "the intended value is the author's call"
7
+ stability: preview
8
+ ported_from: [stylelint/declaration-property-value-no-unknown]
9
+ since: 0.1.0
10
+ ---
11
+
12
+ A property whose value is one keyword from a fixed set — `position`, `display`-like `float` and `clear`, `visibility`, `box-sizing`, `overflow`, border styles and others — is given one of those keywords or a CSS-wide keyword.
13
+
14
+ **Why:** The browser drops a declaration whose value it does not recognise.
15
+
16
+ ```codelaw
17
+ native: css/declaration-property-value-no-unknown
18
+ ```
19
+
20
+ ## How to fix
21
+
22
+ 1. Replace the value with one the property accepts.
23
+
24
+ ## Examples
25
+
26
+ ### CSS
27
+
28
+ #### Don't
29
+
30
+ ```css
31
+ a {
32
+ position: centre;
33
+ }
34
+ ```
35
+
36
+ #### Do
37
+
38
+ ```css
39
+ a {
40
+ position: relative;
41
+ }
42
+ ```
43
+
44
+ ## Differences from the source
45
+
46
+ Checks single-keyword values of about forty keyword-valued properties, from a table written for this pack; stylelint validates every value against the full CSSTree grammar, whose data derives from MDN data (CC0), which codelaw does not ship.
@@ -0,0 +1,31 @@
1
+ # Cases: css/font-family-no-duplicate-names
2
+
3
+ ### case: a quoted keyword differs from the keyword
4
+
5
+ ```css
6
+ a {
7
+ font-family: "serif", serif;
8
+ }
9
+ ```
10
+
11
+ ```expect
12
+ (none)
13
+ ```
14
+
15
+ ### case: duplicates in the font shorthand
16
+
17
+ ```css
18
+ a {
19
+ font: 12px/1.5 Arial, Arial, sans-serif;
20
+ }
21
+ ```
22
+
23
+ ```expect
24
+ 2:25 css/font-family-no-duplicate-names
25
+ ```
26
+
27
+ ```fixed
28
+ a {
29
+ font: 12px/1.5 Arial, sans-serif;
30
+ }
31
+ ```
@@ -0,0 +1,37 @@
1
+ ---
2
+ id: css/font-family-no-duplicate-names
3
+ title: "No font family listed twice"
4
+ languages: [css]
5
+ fix: auto
6
+ stability: preview
7
+ ported_from: [stylelint/font-family-no-duplicate-names]
8
+ since: 0.1.0
9
+ ---
10
+
11
+ A `font-family` list (or the family part of `font`) names each family once. A quoted `"serif"` is a family name, not the `serif` keyword, so the two are different.
12
+
13
+ **Why:** The second mention can never be used, and usually hides a typo.
14
+
15
+ ```codelaw
16
+ native: css/font-family-no-duplicate-names
17
+ ```
18
+
19
+ ## Examples
20
+
21
+ ### CSS
22
+
23
+ #### Don't
24
+
25
+ ```css
26
+ a {
27
+ font-family: Arial, Helvetica, Arial, sans-serif;
28
+ }
29
+ ```
30
+
31
+ #### Do
32
+
33
+ ```css
34
+ a {
35
+ font-family: Arial, Helvetica, sans-serif;
36
+ }
37
+ ```
@@ -0,0 +1,62 @@
1
+ # Cases: css/font-family-no-missing-generic-family-keyword
2
+
3
+ ### case: system fonts in the font shorthand
4
+
5
+ ```css
6
+ a {
7
+ font: caption;
8
+ }
9
+ ```
10
+
11
+ ```expect
12
+ (none)
13
+ ```
14
+
15
+ ### case: values with var()
16
+
17
+ ```css
18
+ a {
19
+ font-family: var(--font), Arial;
20
+ }
21
+ ```
22
+
23
+ ```expect
24
+ (none)
25
+ ```
26
+
27
+ ### case: @font-face names a family
28
+
29
+ ```css
30
+ @font-face {
31
+ font-family: "Inter";
32
+ src: url("inter.woff2");
33
+ }
34
+ ```
35
+
36
+ ```expect
37
+ (none)
38
+ ```
39
+
40
+ ### case: the family part of font
41
+
42
+ ```css
43
+ a {
44
+ font: bold 12px/1.5 Helvetica, Arial;
45
+ }
46
+ ```
47
+
48
+ ```expect
49
+ 2:34 css/font-family-no-missing-generic-family-keyword
50
+ ```
51
+
52
+ ### case: a quoted keyword is a family name
53
+
54
+ ```css
55
+ a {
56
+ font-family: "sans-serif";
57
+ }
58
+ ```
59
+
60
+ ```expect
61
+ 2:16 css/font-family-no-missing-generic-family-keyword
62
+ ```