Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,33 @@ div {
}
```

| Option | Description |
| --------- | ------------------------------------------------------------------- |
| shorthand | Provide false to ignore the shorthand property (`background-image`) |
| longhand | Provide false to ignore the longhand property (`background`) |

```json
{
"rules": {
"plugin/use-defensive-css": [
true,
{ "custom-property-fallbacks": [true, { "longhand": false }] }
]
}
}
```

By default both shorthand and longhand properties are validated. Ignoring either
will allow using that property type without raising issues.

#### ✅ Passing Examples

```css
div {
background-image: url('some-image.jpg');
}
```

### Custom Property Fallbacks

> [Read more about this pattern in Defensive CSS](https://defensivecss.dev/tip/css-variable-fallback/)
Expand Down
26 changes: 23 additions & 3 deletions src/rules/use-defensive-css/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,15 +94,35 @@ const ruleFunction = (_, options) => {
}

/* BACKGROUND REPEAT */
if (options?.['background-repeat']) {
if (decl.prop === 'background' && decl.value.includes('url(')) {
if (
options?.['background-repeat'] &&
(!Array.isArray(options?.['background-repeat']) ||
options['background-repeat'][0])
) {
const backgroundRepeatOptions = {
shorthand: true,
longhand: true,
...(Array.isArray(options['background-repeat'])
? options['background-repeat'][1]
: {}),
};

if (
decl.prop === 'background' &&
backgroundRepeatOptions.shorthand &&
decl.value.includes('url(')
) {
backgroundRepeatProps.hasBackgroundImage = true;
backgroundRepeatProps.isMissingBackgroundRepeat =
!findShorthandBackgroundRepeat(decl.value);
backgroundRepeatProps.nodeToReport = decl;
}

if (decl.prop === 'background-image' && decl.value.includes('url(')) {
if (
decl.prop === 'background-image' &&
backgroundRepeatOptions.longhand &&
decl.value.includes('url(')
) {
backgroundRepeatProps.hasBackgroundImage = true;
backgroundRepeatProps.nodeToReport = decl;
}
Expand Down
75 changes: 75 additions & 0 deletions src/rules/use-defensive-css/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,81 @@ testRule({
],
});

/* eslint-disable-next-line no-undef */
testRule({
ruleName,
config: [true, { 'background-repeat': [true, { longhand: false }] }],
plugins: ['./index.js'],
accept: [
{
code: `div { background: url('some-image.jpg') repeat black top center; }`,
description: "Shorthand background property with 'repeat' value.",
},
{
code: `div { background: url('some-image.jpg') repeat-x black top center; }`,
description: "Shorthand background property with 'repeat-x' value.",
},
{
code: `div { background: url('some-image.jpg') repeat-y black top center; }`,
description: "Shorthand background property with 'repeat-y' value.",
},
{
code: `div { background: url('some-image.jpg') no-repeat black top center; }`,
description: "Shorthand background property with 'no-repeat' value.",
},
{
code: `div { background: url('some-image.jpg') round black top center; }`,
description: "Shorthand background property with 'round' value.",
},
{
code: `div { background: url('some-image.jpg') space black top center; }`,
description: "Shorthand background property with 'space' value.",
},
{
code: `div { background: url('some-image.jpg') space round black top center; }`,
description: "Shorthand background property with 'space round' value.",
},
{
code: `div { background: url('some-image.jpg') black top center; background-repeat: no-repeat; }`,
description:
'Shorthand background property with background-repeat property.',
},
{
code: `div { background-image: url('some-image.jpg'); background-repeat: no-repeat; }`,
description: 'Using background-image with background-repeat properties.',
},
{
code: `div { background-image: linear-gradient(#e66465, #9198e5); }`,
description:
'Using a linear-gradient background image without background repeat is okay.',
},
{
code: `div { background-image: linear-gradient(#e66465, #9198e5), url('some-image.jpg'); background-repeat: no-repeat; }`,
description:
'Using background-image with gradient and url with background-repeat property is okay.',
},
{
code: `div { background-image: url('some-image.jpg'); }`,
description:
'A background-image property without a background-repeat property.',
},
{
code: `div { background-image: linear-gradient(#e66465, #9198e5), url('some-image.jpg'); }`,
description:
'A background-image property with both a gradient and url() but no background-repeat property.',
message: messages.backgroundRepeat(),
},
],

reject: [
{
code: `div { background: url('some-image.jpg') black top center; }`,
description: 'A shorthand background property without a repeat property.',
message: messages.backgroundRepeat(),
},
],
});

/* eslint-disable-next-line no-undef */
testRule({
ruleName,
Expand Down