用 StyleLint 提升代码质量的实战经验分享
先说结论:StyleLint + SCSS 是我团队的标配
别整那些花里胡哨的,我们项目现在统一用 StyleLint 配合 SCSS 做样式校验,配合 Prettier 格式化,跑在 pre-commit 里。虽然有人还在用 ESLint 的 style 插件,或者干脆不写 lint,但我得说一句:真不行。
最近带新人的时候发现,有人还是搞不清 StyleLint 和其他方案到底差在哪,就想着干脆写篇对比文,把我踩过的坑、试过的方案都拎出来讲讲。不是那种“各有优劣”的和稀泥分析,是我个人实战后的看法,有不同意见欢迎评论区对线。
为什么我要用 StyleLint?因为样式真的能写成屎
你有没有遇到过这种 CSS:
- 颜色全写死 #333、#666,没人知道这代表啥
- class 名瞎起,什么 .box1、.div2,重构时根本不敢动
- 嵌套层级深到 5 层以上,一改就崩
- 一个按钮写了三遍 hover 效果,因为拼写不一致
这些都不是代码逻辑问题,但它们会直接拖垮团队协作效率。我就在两个项目里吃过亏:一个是纯手写 CSS 没规范,最后交接时花了三天才理清命名规则;另一个是用了 PostCSS 插件做简单校验,结果根本不支持自定义规则。
所以后来我铁了心要上 StyleLint —— 它能让你的样式代码也拥有“语法洁癖”。
三种主流方案实测对比
目前前端圈常见的样式检查方案大概就这几种:
- 纯靠人工 Code Review(别笑,真有人这么干)
- ESLint 的 react/style 插件(比如 eslint-plugin-jsx-a11y)
- PostCSS 自定义插件做校验
- StyleLint(本文重点)
下面一个个说。
人工 Review?省省吧,不可能每次都看出来
这个就不放代码了,太真实反而尴尬。简单说就是依赖人眼扫描每一个 commit diff,指望同事发现问题。
问题是:人都会累,而且注意力有限。我之前参与的一个紧急项目,连续两周加班到凌晨,Code Review 全靠“差不多得了”,结果上线后发现一堆 z-index 写成了字符串,浏览器直接忽略……
这类低级错误完全可以通过工具拦截,非要用人力扛,纯属浪费生命。
ESLint 能不能搞定样式?半吊子水平
很多人以为 ESLint 插件能覆盖样式问题,比如 eslint-plugin-react 或 jsx-a11y 可以检查 inline-style 是否符合可访问性。
比如这样:
// React 组件中的内联样式
function Button() {
return (
<button style={{ backgroundColor: '#ff0000', color: '#ffffff' }}>
提交
</button>
);
}
ESLint 确实可以提醒你用了 magic number 颜色,但它只能查 JSX 里的 style 对象,对于外部 CSS 文件完全无能为力。
更别说 SCSS、Less 这种预处理器,ESLint 根本看不懂。想让它识别 .scss 文件?得配一堆 parser,折腾半天还报错。
结论:适合极简项目或临时原型,正式项目别指望它。
PostCSS 插件自己写校验?可以但没必要
我知道有些团队喜欢造轮子,比如写个 PostCSS 插件来检测变量使用情况。
// postcss-plugin-no-magic-color.js
module.exports = () => {
return {
postcssPlugin: 'no-magic-color',
Declaration(decl) {
if (decl.value.includes('#') && !decl.value.includes('var(')) {
decl.warn(this.result, '禁止直接使用十六进制颜色');
}
}
};
};
然后在 postcss.config.js 中引入:
module.exports = {
plugins: [
require('./postcss-plugin-no-magic-color')
]
};
这个方案确实能跑通,我也试过。但问题来了:
- 每加一条规则就得写一个插件
- 没法复用社区生态(比如 stylelint-config-standard)
- 错误提示不够友好,还得自己处理报告格式
- 调试麻烦,console.log 都要重启构建流程
折腾了两天,我发现同样的功能 StyleLint 几行配置就能实现,何必重复造轮子?
StyleLint 真香在哪?规则全、生态强、可扩展
回到主角。StyleLint 的核心优势是:它就是一个专为样式设计的 Linter,就像 ESLint 之于 JS。
先上基础配置:
{
"extends": "stylelint-config-standard",
"rules": {
"color-hex-length": "short",
"selector-class-pattern": "^[a-z][a-zA-Z0-9]*$",
"declaration-block-no-redundant-longhand-properties": true,
"no-descending-specificity": null
}
}
再配合 .stylelintignore 忽略第三方库:
node_modules/
dist/
vendor/
*.min.css
然后在 package.json 加脚本:
{
"scripts": {
"lint:styles": "stylelint "src/**/*.scss"",
"lint:styles:fix": "stylelint "src/**/*.scss" --fix"
}
}
还可以集成到编辑器,保存自动 fix。VS Code 装 stylelint 插件就行,开箱即用。
重点是它的规则系统非常灵活。比如我们团队要求所有 class 名必须驼峰式,我就直接改 selector-class-pattern:
"selector-class-pattern": "^[a-z][a-zA-Z0-9]*$"
如果想禁用某些烦人的规则,比如 no-descending-specificity(这条经常误报),直接设为 null 就行,不像 PostCSS 那样要重写逻辑。
和 Prettier 集成要注意!顺序错了直接打架
这里注意我踩过好几次坑:StyleLint 和 Prettier 都能格式化代码,但如果配置不当,会互相覆盖。
正确做法是让 Prettier 专注格式,StyleLint 专注规则,通过 stylelint-config-prettier 关闭所有与 Prettier 冲突的规则。
npm install --save-dev stylelint-config-prettier
{
"extends": [
"stylelint-config-standard",
"stylelint-config-prettier"
]
}
同时确保执行顺序:
"lint:styles": "stylelint "src/**/*.scss" --fix && prettier "src/**/*.scss" --write"
先 StyleLint 修复结构性问题,再用 Prettier 统一缩进换行。反过来的话,Prettier 改完可能又被 StyleLint 判为不合规,无限循环。
SCSS 支持完美吗?基本够用,个别坑要绕
我们项目用的是 SCSS,StyleLint 对 @mixin、@include、变量这些支持都不错。但有一个小坑:如果你用了大量嵌套,且开启 max-nesting-depth 规则,要注意它不会穿透条件语句。
.card {
&__title {
font-size: 16px;
@media (min-width: 768px) {
font-size: 18px;
small {
font-size: 14px; // 这一层会被算作第3层
}
}
}
}
上面这段,small 是嵌套第3层。如果 max-nesting-depth 设为2,就会报错。解决办法要么放宽限制,要么拆分结构。
我个人选择后者 —— 毕竟深层嵌套本身就不利于维护,借着 lint 强制重构也是好事。
我的选型逻辑:宁可严一点,也不能松
总结一下我的偏好:
- 不用人工 Review 做主要防线 —— 不可靠
- 不用 ESLint 查样式 —— 能力边界太窄
- 不用自研 PostCSS 插件 —— 成本高,难维护
- 主推 StyleLint + SCSS + Prettier 组合 —— 生态成熟,配置简单
虽然改完后仍有一两个小问题,比如某些动态生成的 class 会被误伤,但整体收益远大于成本。
这个方案不是最优的,但最简单、最容易落地。尤其适合中大型项目或多人协作场景。
以上是我的对比总结,有不同看法欢迎评论区交流
我知道肯定有人坚持用别的方案,比如 Tailwind 的 className 校验工具,或者用 TypeScript 编译时检查 styled-components。那些也都有道理,但在传统 SCSS/CSS 项目里,StyleLint 依然是我心中的首选。
这个技巧的拓展用法还有很多,比如结合 CI 流程做 PR 拦截、生成违规统计报表,后续会继续分享这类实战经验。

暂无评论