跳到主内容
d.devtul.fun
EN
正则 · Hex Color

十六进制颜色正则

一个能匹配所有合法十六进制颜色的正则,以及一个更硬气的结论:很多时候你压根不该用它。

正则模式

^#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$

匹配三、四、六、八位这四种十六进制颜色写法。其余一律拒绝,包括少了 # 的。

在线测试这个正则

在下面直接改文本 —— 匹配在本机完成,不会上传任何内容。

其它写法

用 i 标志忽略大小写
^#(?:[0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$

去掉 A-F 区间,改成编译时传忽略大小写标志。匹配结果一样,正则会短一点。

# 可省略
^#?(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$

接受不带井号的 1a2b3c。输入框里方便,但得自己决定空值或裸值是什么意思。

这个正则匹配什么

覆盖所有 CSS 十六进制颜色写法的正则:

^#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$

从左到右读:

  • ^# 要求必须有井号。少了它,你匹配的根本不是 CSS 颜色。
  • 非捕获组给出三选一,按顺序尝试:
    • [0-9a-fA-F]{3,4} 覆盖三位 #RGB 和四位 #RGBA 简写。
    • [0-9a-fA-F]{6} 是经典的六位 #RRGGBB。
    • [0-9a-fA-F]{8} 是带透明度的八位 #RRGGBBAA。
  • $ 锚定结尾,尾部多余字符一律拒绝。

为什么 3、4、6、8 位都合法

CSS 定了一条简写规则:在三、四位写法里,每个十六进制数字会被复制一次凑成完整值。于是:

形式例子展开成
#RGB#f0a#ff00aa
#RGBA#f0a8#ff00aa88
#RRGGBB#ff00aa自身
#RRGGBBAA#ff00aa88自身

这就是为什么正则必须同时接受 3 和 4(不能只接受 3)、以及 6 和 8(不能只接受 6)。把位数写死成 {6} 的正则会悄悄把 #fff 判错,而那恰恰是网页上最常见的颜色之一。

忽略大小写的写法

十六进制数字不区分大小写:#FFF 等于 #fff。你可以把字符类写成 [0-9a-fA-F],也可以写成 [0-9a-f] 并在编译时打开忽略大小写标志。两者匹配同样的字符串。选语言里更干净那种就行,但别两种都忘,否则 #ABCDEF 会被拒。

至于要不要允许没有 #,这是个产品决策。在严格的 CSS 语境里井号是强制的;在用户输入框里你可以接受 1a2b3c 然后自己补上井号。上面的主正则要求井号,变体里给了可省略版。

正则判断不了这个颜色能不能渲染

这是核心,值得说直白点:正则只能告诉你一个字符串"长得像"十六进制颜色,却告诉不了你它是不是合法 CSS、会不会真的被应用、在上下文里有没有意义。

在浏览器里,你手里本就有一个好得多的校验器,那就是 CSS 引擎:

function isColor(value) {
  return CSS.supports('color', value);
}

CSS.supports 用的是和浏览器一模一样的解析器,所以它能接受 #fff、rebeccapurple、rgb(0 0 0 / 50%),也能用真正的解析逻辑拒掉胡说八道。它还帮你面向未来:新颜色语法一出来,正则会坏,CSS.supports 不会。

如果你不在浏览器里,那就自己解析,或者依赖一个体积小、经过充分测试的颜色库,而不是手搓正则。正则适合回答"这段日志里有没有像颜色的东西",不适合回答"这到底是不是个真颜色"。

常见错误写法

错误写法问题正确写法
^#[0-9a-f]{6}$把 #fff、#ffff、#ffffffff 全拒了。把 3、4、6、8 四种都收进来。
^[0-9a-f]{6}$忘了强制的 #。要求 #,或 deliberate 地决定不要。
^#[0-9a-fA-F]{8}$漏掉了常见的三、六位写法。四种长度都要。
把 #ffff 和 #ffffff 搞混四位是 RGBA,不是写坏的六位。四位是 RGBA,八位是 RRGGBBAA。

#fff 与 #ffff 的区别

一个高频困惑点:#fff 是三位(简写 RGB)。#ffff 是四位,也就是说 #ffff 是带满透明度的简写 RGBA,并不是写坏的六位颜色。同理,#ffffff 是六位 RGB,#ffffffff 是八位 RGBA。光看位数就能知道你面对的是哪种通道布局,正则里的分支也正是照此而来。

从文本里提取所有颜色

有时你要的不是校验单个值,而是从一大段文本(样式表 dumped 出来的内容、日志、用户粘贴)里把所有十六进制颜色抠出来。这时去掉锚点,开全局标志:

/#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})/g

那个  边界能阻止 #1234567 把前六位当成颜色匹配走。记住这叫"提取",不是"校验意图":一串碰巧长得像颜色的十六进制,并不自动就是页面会用到的颜色。

什么时候正则才是对的

公平地说,在很窄的场景里正则有它的位置:

  • 在没有 CSS 解析器的非浏览器语言里,对一个值做快速体检。
  • 从日志或粘贴文本里快速扫出像颜色那样的 token。
  • 在更深层解析之前,于表单边界做一次快速拒绝。

但只要问题变成"这个颜色到底会不会被用上",就去找平台自带的解析器。正则回答的是"它看起来对不对",解析器回答的是"它到底对不对"。

常见问题

正则够不够校验 CSS 颜色?

不够。它只检查字符串长得像不像颜色。在浏览器里要用 CSS.supports() 做真正校验。

为什么 #fff 能用,我的正则却拒了它?

你把位数写死成六位了。#fff 是三位简写,每位会被复制一次。

#ffff 和 #ffffff 有什么不同?

四位是带透明度的简写 RGBA,六位是 RGB。两者通道布局不同。

要不要允许不带 # 的十六进制颜色?

只在用户输入时允许,并且自己补上井号。严格 CSS 里 # 是强制的。

其它正则速查

打开完整的正则测试器