同一个蓝色,七种写法

#0969da
#069da 非法
rgb(9 105 218)
hsl(212 92% 45%)
hwb(212 4% 15%)
oklch(52% .19 253)
royalblue
/* 十六进制 */
#0969da            /* 6 位:RRGGBB */
#0969da80          /* 8 位:RRGGBBAA,最后两位是透明度(00 全透明,FF 不透明) */
#069               /* 3 位缩写 = #006699,只有每对数字相同才能缩写 */

/* 函数式:现代写法用空格分隔,不需要逗号 */
rgb(9 105 218)      rgb(9, 105, 218)        /* 新/旧语法都支持 */
rgb(9 105 218 / 0.5)   rgb(9 105 218 / 50%)
hsl(212 92% 45%)     /* 色相 0–360,饱和度、亮度百分比 */
hsl(212 92% 45% / 50%)
hwb(212 4% 15%)      /* 白量、黑量,比 hsl 更符合「调深浅」的直觉 */
oklch(52% 0.19 253)  /* 感知均匀:亮度百分比越接近视觉明度,彩度 0–0.4 左右 */
lab(...)  lch(...)  color(display-p3 …)  color(srgb …)  /* 其它色彩空间 */
transparent  currentColor  inherit  /* 三个特殊关键字 */

上面第二个格子故意写成 #069da:5 位十六进制非法,浏览器整条声明丢弃,所以那块是默认底色——这就是「颜色不生效」最常见的一个原因,缩写只能 3 位或 6 位。

该选哪种写法

写法适合原因
#RRGGBB固定的品牌色、设计稿直接取色最短、工具里最好读
#RRGGBBAA需要一次性写透明色一个 token 搞定,不用函数
hsl() / hwb()需要成组地调明暗、生成变体改一个数字就能出一系列色阶,比改 hex 直观得多
rgb(… / a)由 JS 计算出的颜色、需要单独控制透明度与取值 API 天然一致
oklch()做色阶系统、深浅主题HSL 的「50% 亮度」在不同色相下视觉明度差很多(黄色亮、蓝紫暗);OKLCH 是感知均匀的,同一 L 值的各色看起来真的同样亮
颜色关键字临时试色147 个 CSS 命名色(royalblue 等)加 transparent/currentColor;正式项目不建议,读代码时要查表

透明度:alpha 与 opacity 不是一件事

rgb(… / .5)
#0969da80
hsl(… / 50%)
/* 颜色的 alpha:只有这一层颜色透明,文字仍然清晰 */
background: rgb(9 105 218 / 0.5);

/* 元素的 opacity:整层(含文字、子元素、边框)一起透明,并会创建层叠上下文 */
opacity: .5;

currentColor 是个实用工具:它取当前元素的 color 值,所以 border-color: currentColor、box-shadow: 0 0 0 3px currentColor 会随主题自动跟随,不需要额外维护变量。

与暗色主题的配合

/* 不要把颜色硬写进组件,交给变量(第十四章展开) */
:root { --c-primary: #0969da; --c-bg: #fff; --c-text: #24292f; }
html[data-theme='dark'] { --c-primary: #6aa8ff; --c-bg: #0d1117; --c-text: #e6edf3; }

.card { background: var(--c-bg); color: var(--c-text); border-color: var(--c-primary); }

暗色主题下不要简单地把颜色取反:深蓝底配高饱和品牌色容易「发光」刺眼,通常要把饱和度降下来、明度提上去(这正是 oklch() 好用的地方——只调 L 与 C,保持色相不变)。另外 color-scheme: light dark 这一行能让浏览器的默认控件、滚动条、表单底色一起切换,成本极低但收益明显。