A sharable stylelint config object that enforces Cloud Four's CSS Standards
Note that this config mostly just extends stylelint-config-standard, plus stylelint-config-standard-scss for Sass files, and any additions or changes from those standards should be well-documented here to explain the deviation.
Install stylelint and stylelint-config-cloudfour:
npm install stylelint stylelint-config-cloudfour --save-dev
If you've installed stylelint-config-cloudfour locally within your project, just set your stylelint config to:
{
"extends": "stylelint-config-cloudfour"
}You'll probably also want to add a script to your package.json file to make it easier to run Stylelint with this config:
"scripts": {
"lint:css": "stylelint '**/*.css'"
}Sass rules and the SCSS parser only apply to .scss files. Plain .css files are parsed as CSS, so they get Stylelint's full set of validity rules, and none of the Sass rules. You don't need to configure anything for this. If your project uses Sass, include .scss files in your lint script:
"scripts": {
"lint:css": "stylelint '**/*.{css,scss}'"
}Stylelint chooses a config for each file, not for each <style> block. Since this config picks the Sass rules by file extension, files that embed styles, such as Vue components, get the CSS rules for every <style> block, including <style lang="scss"> blocks. That works well if your components only use CSS. But if they use Sass, the CSS rules will report Sass features as errors (such as @use, @include, and @mixin, which are unknown at-rules in CSS), and the Sass rules won't run.
If your components use Sass, you can apply the Sass config to them with stylelint-config-cloudfour/scss:
{
extends: ["stylelint-config-cloudfour"],
overrides: [
{
files: ["**/*.vue"],
extends: ["stylelint-config-cloudfour/scss"],
customSyntax: "postcss-html",
},
],
}Now every <style> block in your components is linted with the Sass rules.
This config can't fully support components that mix Sass and plain CSS. Because Stylelint applies one config to the whole file, enabling the Sass config means every <style> block is linted as Sass, even blocks that are plain CSS.
That won't cause false errors, since Sass is a superset of CSS. However, stylelint-config-standard-scss turns off some CSS rules because they misreport Sass syntax, and those rules won't run on any block. So your plain CSS won't be checked for these:
annotation-no-unknownat-rule-descriptor-no-unknownat-rule-descriptor-value-no-unknownat-rule-prelude-no-invaliddeclaration-property-value-no-unknownmedia-feature-name-value-no-unknownmedia-query-no-invalidno-duplicate-selectors
We recommend using Prettier to format your CSS and Sass, and this config works with it without any extra setup.
As of v16, Stylelint removed its formatting rules, leaving formatting to dedicated tools like Prettier. That's why stylelint-config-prettier, which used to turn those rules off, is no longer needed. However, stylelint-config-standard-scss still turns on formatting rules from stylelint-scss, such as scss/operator-no-newline-after. Some of them conflict with how Prettier formats Sass. To match the intent of Stylelint's decision, this config turns those formatting rules off.
To change or add rules, add a rules key to your config. Your rules take precedence over this config's.
For example, to teach at-rule-no-unknown about an at-rule from a PostCSS plugin, turn off selector-not-notation, and allow only certain units with unit-allowed-list:
{
extends: ["stylelint-config-cloudfour"],
rules: {
"at-rule-no-unknown": [true, { ignoreAtRules: ["define-mixin"] }],
"selector-not-notation": null,
"unit-allowed-list": ["em", "rem", "%", "s"],
},
}Rules in your rules key apply to every file, including .scss files. That matters for rules that this config only turns off for Sass. For example, at-rule-no-unknown is off for .scss files because it reports Sass at-rules like @use and @include as unknown, and setting it in your rules turns it back on for them.
If your project lints both CSS and Sass, use overrides to change a rule for one file type only:
{
extends: ["stylelint-config-cloudfour"],
overrides: [
{
files: ["**/*.css"],
rules: {
"at-rule-no-unknown": [true, { ignoreAtRules: ["define-mixin"] }],
},
},
],
}No. This config disables the kebab-case naming patterns from stylelint-config-standard-scss for classes, IDs, custom properties, custom media, keyframes, cascade layers, containers, and Sass mixins, functions, variables, and placeholders, so that it works with naming conventions like SUIT CSS. If you want to enforce a convention, add the pattern rules or a plugin like stylelint-selector-bem-pattern to your own config.
Yes. Logical properties, such as margin-inline-start instead of margin-left, describe layout relative to the text direction instead of the screen. This config flags physical properties, units, and keywords, and stylelint --fix converts them for you:
| Physical | Logical |
|---|---|
margin-left, padding-top, border-right |
margin-inline-start, padding-block-start, border-inline-end |
top, left |
inset-block-start, inset-inline-start |
width, max-height |
inline-size, max-block-size |
100vw, 50dvh |
100vi, 50dvb |
float: left, text-align: right |
float: inline-start, text-align: end |
Two exceptions are allowed, because browsers don't fully support their logical versions yet:
overflow-xandoverflow-y:overflow-inlineandoverflow-blockneed Safari 26 or later (#662).- Physical keywords in
offset-anchorandoffset-position, such asleft top: no browser supports the logical keywords yet (#663).
Shorthand properties with physical sides, such as margin: 0 1rem 0 2rem, aren't flagged yet (stylelint/stylelint#9420).
Stylelint can only convert physical properties if it knows the page's writing direction, because a physical side like left maps to a different logical side in each direction. This config assumes a left-to-right, top-to-bottom language like English. If your project uses another writing direction, such as right-to-left for Arabic or Hebrew, override it in your config:
{
extends: ["stylelint-config-cloudfour"],
languageOptions: {
directionality: {
block: "top-to-bottom",
inline: "right-to-left",
},
},
}On an element with a vertical writing-mode, such as writing-mode: vertical-rl, the inline direction runs top to bottom. So logical properties on that element map to different physical sides: inline-size sets its height, not its width. If you convert physical properties on these elements, check that they still look right, or keep the physical properties with a stylelint-disable comment.
To keep using physical properties, turn off the rules in your config:
rules: {
"property-layout-mappings": null,
"unit-layout-mappings": null,
"value-keyword-layout-mappings": null,
}- stylelint-config-standard: The standard shareable config for Stylelint.
- stylelint-config-standard-scss: The standard shareable SCSS config for Stylelint.
.scssfiles only.
- stylelint-declaration-block-no-ignored-properties: Disallow property values that are ignored due to another property value in the same rule.
- stylelint-high-performance-animation: Prevent the use of low performance animation and transition properties.
- stylelint-order: Enforce the order of content within declaration blocks.
This is a list of the lints turned on in this configuration (beyond the ones that come from stylelint-config-standard and stylelint-config-standard-scss), and what they do.
at-rule-empty-line-before: Require an empty line before at-rules. disabled, because it requires an empty line before blockless at-rules like@include, which looks awkward among declarations (#7). The option that would allow this won't be added, since Stylelint no longer adds features to formatting rules.comment-empty-line-before: Require an empty line before comments. overriding the standard rule to exclude the first nested comment in a block.import-notation: Require@importpaths to be strings, such as@import 'foo.css', rather thanurl(). overriding the standard rule to match the Sass convention.no-descending-specificity: Disallow selectors of lower specificity from coming after overriding selectors of higher specificity. disabled due to false positives in SCSS contexts.rule-empty-line-before: Require an empty line before multi-line rules. overriding the standard rule to exclude the first multi-line rule in a block, and to ignore rules following comments.
property-layout-mappings: Require logical properties, such asmargin-inline-startinstead ofmargin-left. ignoringoverflow-xandoverflow-y.unit-layout-mappings: Require logical units, such asviinstead ofvw.value-keyword-layout-mappings: Require logical keywords, such asfloat: inline-startinstead offloat: left. ignoringoffset-anchorandoffset-position.
order/order: Specifies the order of content within declaration blocks: Sass variables, custom properties, declarations, nested rules.@includecan go anywhere, since its position decides which styles win.order/properties-alphabetical-order: Specify the alphabetical order of properties within declaration blocks.
These only apply to .scss files. The Sass formatting rules from stylelint-config-standard-scss, such as scss/operator-no-newline-after, are turned off, since Prettier handles formatting.
at-rule-disallowed-list: Disallow use of@extendbecause it's considered an anti-pattern, and@importbecause it's deprecatedscss/declaration-nested-properties: Disallow SCSS nested property groups, such asfont { size: 16px; weight: 700; }.scss/selector-no-redundant-nesting-selector: Disallow redundant nesting selectors (&).
plugin/declaration-block-no-ignored-properties: Disallow property values that are ignored due to another property value in the same rule, such aswidthwithdisplay: inline.plugin/no-low-performance-animation-properties: Prevent the use of low performance animation and transition properties that triggerlayout.