stylelint 的 function-disallowed-list 规则:禁用 CSS 函数的黑名单配置实战与源码解析
2026/9/23 19:02:02 网站建设 项目流程

stylelint 的 function-disallowed-list 规则:禁用 CSS 函数的黑名单配置实战与源码解析

【免费下载链接】stylelintA mighty CSS linter that helps you avoid errors and enforce conventions.项目地址: https://gitcode.com/gh_mirrors/st/stylelint

stylelint 的function-disallowed-list规则允许你指定一组禁止在样式表中出现的 CSS 函数(如scale()rgba()),凡是命中黑名单的函数调用都会触发警告。本文以该规则为核心,完整讲解它的配置选项、匹配语义、嵌套场景与自定义消息,并结合 lib/rules/function-disallowed-list/index.mjs 的源码实现与 lib/rules/function-disallowed-list/tests/index.mjs 的测试用例,让你不仅会配置,还理解它底层如何解析、匹配与报告问题。

规则概述:管住样式里的"危险函数"

CSS 函数种类繁多,从颜色函数rgb()rgba()hsl(),到变换函数scale()rotate()translateX(),再到渐变函数linear-gradient()radial-gradient()。团队可能出于兼容性、性能或代码风格约定,希望某些函数不再被使用。function-disallowed-list就是为此设计的黑名单规则:

a { transform: scale(1); } /** ↑ * 这个函数会被命中黑名单并报告 */

它与配套的白名单规则 function-allowed-list 互补:一个"只许用这些",一个"不许用这些"。两个规则都已注册在 lib/rules/index.mjs 的规则清单中,可直接通过配置文件启用。

配置方式:数组形式的黑名单

该规则的选项为Array<string>,数组中的每一项可以是:

  • 函数名字符串,例如"scale"
  • /开头和结尾的正则表达式字符串,例如"/^(-moz-)?linear-gradient$/"
{ "function-disallowed-list": ["scale", "rgba", "/^(-moz-)?linear-gradient$/"] }

将上面的配置应用到以下样式,三处函数调用会全部被判定为问题:

a { transform: scale(1); } a { color: rgba(0, 0, 0, 0.5); } a { background: red, -moz-linear-gradient(45deg, blue, red); }

而不包含任何禁用函数的样式则不会报错:

a { background: red; }

tests/index.mjs 的测试中,上述三组命中场景对应的报告位置分别为第 1 行第 16–21 列(scale)、第 1 行第 12–16 列(rgba)与第 1 行第 22–42 列(-moz-linear-gradient),说明规则会精确地定位到函数名本身而非整条声明。

匹配语义:字符串精确匹配,正则按需使用

字符串:大小写敏感的精确匹配

当配置项是普通字符串时,规则对函数名做严格相等比较(value === comparison,见 matchesStringOrRegExp.mjs),因此默认大小写敏感。测试用例明确覆盖了这一行为:

  • 配置["scale"]时,scale(1)报错;
  • SCALE(1)sCaLe(1)均被接受(见测试第 13–17 行)。

正则字符串:以/包裹即被识别为正则

任何以/开头、以/结尾的配置项会被解释为正则表达式;若以/<regex>/i形式结尾,还会附加i修饰符实现忽略大小写匹配。同样在 matchesStringOrRegExp.mjs 中可以看到,字符串形式正则会被new RegExp()重新构造。

例如配置"/^(-moz-)?linear-gradient$/",则linear-gradient(...)-moz-linear-gradient(...)都会被命中,而-webkit-radial-gradient(...)不会。测试第 29 行也验证了这一点。

正则对象:大小写混合场景

除了字符串,配置文件如果是 JS 格式,也可以直接传入RegExp对象。测试第 153 行的config: [/rgb/]会同时命中rgb()rgba()(因为/rgb/是子串匹配),而不会命中hsl()

测试第 184 行的组合配置['skewx', 'translateX', 'SCALEX', '/rotate/i', '/MATRIX/']则展示了一个更贴近实战的混合用法:

  • 字符串'skewx':仅命中全小写的skewx(10deg),不命中stewX(10deg)
  • 字符串'translateX':仅命中精确大小写的translateX(5px)translateY(5px)不受影响;
  • 字符串'SCALEX':仅命中全大写的SCALEX(1)scaleX(1)不受影响;
  • 正则'/rotate/i':大小写不敏感,rotatexrotateXROTATEX全部命中;
  • 正则'/MATRIX/':子串匹配,MATRIX3d(a1)命中,而matrix3d(a1)(小写)不命中。

提示:字符串黑名单适合精确禁用少数函数;正则黑名单适合批量拦截一类函数(如所有带厂商前缀的渐变、所有translate*变换)。

源码原理:一次函数调用如何被"揪出来"

规则实现位于 lib/rules/function-disallowed-list/index.mjs,整个检查流程可以拆解为五步:

1. 校验选项

规则通过validateOptions检查主选项是否为字符串或正则的数组,非法配置会在启动时给出配置错误而不是静默失效:

const validOptions = validateOptions(result, ruleName, { actual: primary, possible: [isString, isRegExp], });

同时规则声明了rule.primaryOptionArray = true,表明主选项必须是数组形式。

2. 遍历所有声明

通过root.walkDecls遍历样式树中的每一条decl(声明),并用decl.value.includes('(')做快速过滤——没有括号的值不可能包含函数调用,直接跳过,避免无谓的解析开销。

3. 用 postcss-value-parser 解析值

对候选声明,使用postcss-value-parser将值解析为节点树,并walk每个节点。借助 typeGuards.mjs 中的isValueFunction判断节点类型是否为function

4. 排除非标准语法函数

isStandardSyntaxFunction.mjs 会排除三种"看起来像函数但不是普通 CSS 函数"的节点:

  • 没有名字的括号内容(如 Sass 列表,测试第 38 行的$scale: (value, value2)正是此类场景,会被忽略);
  • #{...}形式的插值(如 Sass/Less 插值);
  • ${...}与反引号形式的 CSS-in-JS 插值。

这一设计保证了规则不会误伤预处理器变量、插值表达式和 CSS-in-JS 模板语法。

5. 匹配并精确报告

函数名与黑名单经matchesStringOrRegExp比对,命中后利用declarationValueIndex(decl) + sourceIndex计算出函数名在整条声明中的起始位置,调用report输出警告。从测试的column断言可以看到,报告位置精确指向函数名(例如scale(1)报在第 16 列起、transform: scale(1)中的空格变化会同步改变列号),这对编辑器的 inline 提示非常友好。

嵌套场景:函数套函数也逃不掉

CSS 中函数可以互相嵌套,例如:

a { color: color(rgba(0, 0, 0, 0.5) lightness(50%)); }

valueParserwalk会遍历所有层级的函数节点,因此嵌套在color()内部的rgba()同样会被检测。测试第 93 行正是该场景:配置['rgba', 'scale', ...]时,color(rgba(...) lightness(...))中的rgba被精确报告在第 18–22 列;@media规则内的声明(测试第 108 行)同样会被覆盖,因为walkDecls作用于整棵样式树。

自定义提示消息:让报错更有指导性

该规则支持 1 个 message 参数:被禁用的函数名。你可以在配置文件的 secondary options 中使用message字段定制提示语。消息格式与 docs/user-guide/configure.md 中描述的通用机制一致:

  • 在 JS/TS 格式的配置中,message可以是接收函数名参数的函数:
export default { rules: { "function-disallowed-list": [ ["scale", "rgba"], { message: (name) => `请勿使用已废弃的函数 "${name}",改用推荐写法` } ] } };
  • 在 JSON 配置中,使用printf风格的%s占位符:
{ "rules": { "function-disallowed-list": [ ["scale", "rgba"], { "message": "Disallowed function \"%s\" is not allowed in this project" } ] } }

规则默认消息由 ruleMessages.mjs 统一拼接而成,即`Disallowed function "${name}" (function-disallowed-list)`,其中(function-disallowed-list)后缀会自动追加,便于在多个规则同时报错时快速定位来源。

如何验证与调试

仓库为每条规则都配备了完整的测试套件,规则测试位于 lib/rules/function-disallowed-list/tests/index.mjs,覆盖了大小写敏感、正则字符串、正则对象、嵌套函数、Sass 列表忽略、@media内声明、报告行列位置等场景。如果你想在本地验证自己配置的效果,可以使用 stylelint CLI 配合一个最小配置运行:

npx stylelint "**/*.css" --config .stylelintrc.json

或在 Node 中通过stylelint.lintAPI 检查(参见 docs/user-guide/node-api.md)。新增黑名单条目后,建议同时为它补一条 accept/reject 测试,遵循仓库测试规范(详见 docs/contributor-guide/rules.md)。

实战建议与注意事项

  1. 与白名单规则二选一function-disallowed-list与 function-allowed-list 功能相反,同时启用会让配置难以维护,建议根据团队风格选择其一。
  2. 注意大小写语义:字符串匹配默认大小写敏感,容易漏掉Scale()之类的写法;若想彻底封禁某函数,推荐使用带i修饰符的正则(如"/^scale$/i")。
  3. 善用正则批量拦截:针对渐变、变换、颜色等函数族编写正则,比逐个枚举字符串更省心,例如"/^(-webkit-|-moz-)?(linear|radial)-gradient$/"
  4. 预处理与 CSS-in-JS 不受影响:Sass 列表、插值表达式和 CSS-in-JS 模板语法已被 isStandardSyntaxFunction.mjs 显式排除,不会产生误报。
  5. 配合自定义 message 提供迁移指引:黑名单规则的价值不仅在"禁止",更在于"告知替代方案",善用message参数告诉开发者该改用哪个函数,能显著降低规则上线时的抵触成本。

【免费下载链接】stylelintA mighty CSS linter that helps you avoid errors and enforce conventions.项目地址: https://gitcode.com/gh_mirrors/st/stylelint

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询