Stylelint 是 CSS/SCSS 的静态分析工具,用于检查其中的违规和错误。
1. 环境要求
v16 以上的 Stylelint,支持 Node.js 的版本为 v18.12.0+。
在命令行工具中输入以下内容后回车,来查看当前系统中 Node.js 的版本。
node -v
Node.js 推荐使用 v18.20.3+ 或者 v20.13.1+。
这里使用的包管理器是 PNPM,版本为 v9.4.0。
2 安装
2.1 针对 CSS
pnpm install -D stylelint stylelint-config-standard stylelint-order
2.2 针对 SCSS(包含CSS)
pnpm install -D stylelint stylelint-order stylelint-config-standard stylelint-config-standard-scss stylelint-config-sass-guidelines stylelint-scss
2.3 在 HTML/Vue 中使用
pnpm install -D postcss-html
3 配置
在项目根目录下创建 stylelint.config.js 文件,根据样式文件类型(CSS/SCSS)填入以下内容:
3.1 针对 CSS
export default {
// 继承已有配置 如果规则与自己想要的冲突 可以在下面rules中修改规则
extends: ['stylelint-config-standard'],
// 插件是由社区创建的规则或规则集 按照规则对CSS属性进行排序
plugins: [
// 指定排序,比如声明的块内(插件包)属性的顺序
'stylelint-order',
],
rules: {
// 允许的最大嵌套深度为 3
'max-nesting-depth': 3,
// 屏蔽一些scss等语法检查
'at-rule-no-unknown': [
true,
{
ignoreAtRules: [
'extend',
'at-root',
'debug',
'warn',
'error',
'if',
'else',
'for',
'each',
'while',
'mixin',
'include',
'content',
'return',
'function',
],
},
],
// 屏蔽没有申明通用字体
'font-family-no-missing-generic-family-keyword': null,
// ID选择器 最多使用一个
'selector-max-id': 1,
// 不允许使用的选择器的类型
'selector-no-qualifying-type': null,
// 屏蔽类选择器的检查,以确保使用字符 __
'selector-class-pattern': null,
// 允许的最大复合选择器为 5
'selector-max-compound-selectors': 5,
// 属性排序规则
'order/properties-order': [
[
'content',
'position',
'top',
'right',
'bottom',
'left',
'z-index',
'display',
'vertical-align',
'flex',
'flex-grow',
'flex-shrink',
'flex-basis',
'flex-direction',
'flex-flow',
'flex-wrap',
'grid',
'grid-area',
'grid-template',
'grid-template-areas',
'grid-template-rows',
'grid-template-columns',
'grid-row',
'grid-row-start',
'grid-row-end',
'grid-column',
'grid-column-start',
'grid-column-end',
'grid-auto-rows',
'grid-auto-columns',
'grid-auto-flow',
'grid-gap',
'grid-row-gap',
'grid-column-gap',
'gap',
'row-gap',
'column-gap',
'align-content',
'align-items',
'align-self',
'justify-content',
'justify-items',
'justify-self',
'order',
'float',
'clear',
'object-fit',
'overflow',
'overflow-x',
'overflow-y',
'overflow-scrolling',
'clip',
//
'box-sizing',
'width',
'min-width',
'max-width',
'height',
'min-height',
'max-height',
'margin',
'margin-top',
'margin-right',
'margin-bottom',
'margin-left',
'padding',
'padding-top',
'padding-right',
'padding-bottom',
'padding-left',
'border',
'border-spacing',
'border-collapse',
'border-width',
'border-style',
'border-color',
'border-top',
'border-top-width',
'border-top-style',
'border-top-color',
'border-right',
'border-right-width',
'border-right-style',
'border-right-color',
'border-bottom',
'border-bottom-width',
'border-bottom-style',
'border-bottom-color',
'border-left',
'border-left-width',
'border-left-style',
'border-left-color',
'border-radius',
'border-top-left-radius',
'border-top-right-radius',
'border-bottom-right-radius',
'border-bottom-left-radius',
'border-image',
'border-image-source',
'border-image-slice',
'border-image-width',
'border-image-outset',
'border-image-repeat',
'border-top-image',
'border-right-image',
'border-bottom-image',
'border-left-image',
'border-corner-image',
'border-top-left-image',
'border-top-right-image',
'border-bottom-right-image',
'border-bottom-left-image',
//
'background',
'background-color',
'background-image',
'background-attachment',
'background-position',
'background-position-x',
'background-position-y',
'background-clip',
'background-origin',
'background-size',
'background-repeat',
'color',
'box-decoration-break',
'box-shadow',
'outline',
'outline-width',
'outline-style',
'outline-color',
'outline-offset',
'table-layout',
'caption-side',
'empty-cells',
'list-style',
'list-style-position',
'list-style-type',
'list-style-image',
//
'font',
'font-weight',
'font-style',
'font-variant',
'font-size-adjust',
'font-stretch',
'font-size',
'font-family',
'src',
'line-height',
'letter-spacing',
'quotes',
'counter-increment',
'counter-reset',
'-ms-writing-mode',
'text-align',
'text-align-last',
'text-decoration',
'text-emphasis',
'text-emphasis-position',
'text-emphasis-style',
'text-emphasis-color',
'text-indent',
'text-justify',
'text-outline',
'text-transform',
'text-wrap',
'text-overflow',
'text-overflow-ellipsis',
'text-overflow-mode',
'text-shadow',
'white-space',
'word-spacing',
'word-wrap',
'word-break',
'overflow-wrap',
'tab-size',
'hyphens',
'interpolation-mode',
//
'opacity',
'visibility',
'filter',
'resize',
'cursor',
'pointer-events',
'user-select',
//
'unicode-bidi',
'direction',
'columns',
'column-span',
'column-width',
'column-count',
'column-fill',
'column-gap',
'column-rule',
'column-rule-width',
'column-rule-style',
'column-rule-color',
'break-before',
'break-inside',
'break-after',
'page-break-before',
'page-break-inside',
'page-break-after',
'orphans',
'widows',
'zoom',
'max-zoom',
'min-zoom',
'user-zoom',
'orientation',
'fill',
'stroke',
//
'transition',
'transition-delay',
'transition-timing-function',
'transition-duration',
'transition-property',
'transform',
'transform-origin',
'animation',
'animation-name',
'animation-duration',
'animation-play-state',
'animation-timing-function',
'animation-delay',
'animation-iteration-count',
'animation-direction',
'animation-fill-mode',
],
{
unspecified: 'bottom',
severity: 'warning',
},
],
// 屏蔽属性按字母顺序检查
'order/properties-alphabetical-order': null,
},
};
3.2 针对 SCSS
export default {
// 继承已有配置 如果规则与自己想要的冲突 可以在下面rules中修改规则
extends: [
'stylelint-config-standard',
'stylelint-config-standard-scss',
'stylelint-config-sass-guidelines',
],
// 插件是由社区创建的规则或规则集 按照规则对CSS属性进行排序
plugins: [
// 执行各种各样的 SCSS语法特性检测规则(插件包)
'stylelint-scss',
// 指定排序,比如声明的块内(插件包)属性的顺序
'stylelint-order',
],
rules: {
// 允许的最大嵌套深度为 3
'max-nesting-depth': 3,
// 屏蔽一些scss等语法检查
'at-rule-no-unknown': [
true,
{
ignoreAtRules: [
'extend',
'at-root',
'debug',
'warn',
'error',
'if',
'else',
'for',
'each',
'while',
'mixin',
'include',
'content',
'return',
'function',
],
},
],
// 屏蔽没有申明通用字体
'font-family-no-missing-generic-family-keyword': null,
// ID选择器 最多使用一个
'selector-max-id': 1,
// 不允许使用的选择器的类型
'selector-no-qualifying-type': null,
// 屏蔽类选择器的检查,以确保使用字符 __
'selector-class-pattern': null,
// 允许的最大复合选择器为 5
'selector-max-compound-selectors': 5,
// 属性排序规则
'order/properties-order': [
[
'content',
'position',
'top',
'right',
'bottom',
'left',
'z-index',
'display',
'vertical-align',
'flex',
'flex-grow',
'flex-shrink',
'flex-basis',
'flex-direction',
'flex-flow',
'flex-wrap',
'grid',
'grid-area',
'grid-template',
'grid-template-areas',
'grid-template-rows',
'grid-template-columns',
'grid-row',
'grid-row-start',
'grid-row-end',
'grid-column',
'grid-column-start',
'grid-column-end',
'grid-auto-rows',
'grid-auto-columns',
'grid-auto-flow',
'grid-gap',
'grid-row-gap',
'grid-column-gap',
'gap',
'row-gap',
'column-gap',
'align-content',
'align-items',
'align-self',
'justify-content',
'justify-items',
'justify-self',
'order',
'float',
'clear',
'object-fit',
'overflow',
'overflow-x',
'overflow-y',
'overflow-scrolling',
'clip',
//
'box-sizing',
'width',
'min-width',
'max-width',
'height',
'min-height',
'max-height',
'margin',
'margin-top',
'margin-right',
'margin-bottom',
'margin-left',
'padding',
'padding-top',
'padding-right',
'padding-bottom',
'padding-left',
'border',
'border-spacing',
'border-collapse',
'border-width',
'border-style',
'border-color',
'border-top',
'border-top-width',
'border-top-style',
'border-top-color',
'border-right',
'border-right-width',
'border-right-style',
'border-right-color',
'border-bottom',
'border-bottom-width',
'border-bottom-style',
'border-bottom-color',
'border-left',
'border-left-width',
'border-left-style',
'border-left-color',
'border-radius',
'border-top-left-radius',
'border-top-right-radius',
'border-bottom-right-radius',
'border-bottom-left-radius',
'border-image',
'border-image-source',
'border-image-slice',
'border-image-width',
'border-image-outset',
'border-image-repeat',
'border-top-image',
'border-right-image',
'border-bottom-image',
'border-left-image',
'border-corner-image',
'border-top-left-image',
'border-top-right-image',
'border-bottom-right-image',
'border-bottom-left-image',
//
'background',
'background-color',
'background-image',
'background-attachment',
'background-position',
'background-position-x',
'background-position-y',
'background-clip',
'background-origin',
'background-size',
'background-repeat',
'color',
'box-decoration-break',
'box-shadow',
'outline',
'outline-width',
'outline-style',
'outline-color',
'outline-offset',
'table-layout',
'caption-side',
'empty-cells',
'list-style',
'list-style-position',
'list-style-type',
'list-style-image',
//
'font',
'font-weight',
'font-style',
'font-variant',
'font-size-adjust',
'font-stretch',
'font-size',
'font-family',
'src',
'line-height',
'letter-spacing',
'quotes',
'counter-increment',
'counter-reset',
'-ms-writing-mode',
'text-align',
'text-align-last',
'text-decoration',
'text-emphasis',
'text-emphasis-position',
'text-emphasis-style',
'text-emphasis-color',
'text-indent',
'text-justify',
'text-outline',
'text-transform',
'text-wrap',
'text-overflow',
'text-overflow-ellipsis',
'text-overflow-mode',
'text-shadow',
'white-space',
'word-spacing',
'word-wrap',
'word-break',
'overflow-wrap',
'tab-size',
'hyphens',
'interpolation-mode',
//
'opacity',
'visibility',
'filter',
'resize',
'cursor',
'pointer-events',
'user-select',
//
'unicode-bidi',
'direction',
'columns',
'column-span',
'column-width',
'column-count',
'column-fill',
'column-gap',
'column-rule',
'column-rule-width',
'column-rule-style',
'column-rule-color',
'break-before',
'break-inside',
'break-after',
'page-break-before',
'page-break-inside',
'page-break-after',
'orphans',
'widows',
'zoom',
'max-zoom',
'min-zoom',
'user-zoom',
'orientation',
'fill',
'stroke',
//
'transition',
'transition-delay',
'transition-timing-function',
'transition-duration',
'transition-property',
'transform',
'transform-origin',
'animation',
'animation-name',
'animation-duration',
'animation-play-state',
'animation-timing-function',
'animation-delay',
'animation-iteration-count',
'animation-direction',
'animation-fill-mode',
],
{
unspecified: 'bottom',
severity: 'warning',
},
],
// 屏蔽属性按字母顺序检查
'order/properties-alphabetical-order': null,
},
};
3.3 在 HTML/Vue 中使用
在根节点加入 customSyntax: ‘postcss-html’:
{
plugins: ...
customSyntax: 'postcss-html',
rules: ...
}
4 结合 Husky
利用 Husky 在 git commit 时自动校验文件中的样式内容,如不符合规范,则文件不能被 commit。详细操作见《前端工程化工具系列(五)—— Husky(v9.0.11)&lint-staged(v15.2.5):代码提交前的自动审查利器》中的 2.1节。
5 结合 VS Code
配合 VS Code 插件,可在做文件保存时自动修复错误。详细操作见《前端工程化工具系列(六)—— VS Code(v1.89.1):强大的代码编辑器》。