Canvas不解析CSS变量,var(--primary)会静默回退为黑色;必须用getComputedStyle().getPropertyValue()获取计算后的颜色值并.trim(),且主题切换后需主动重绘。

ctx.fillStyle = "var(--primary)" 为什么画出来是黑的
Canvas 2D 上下文根本不解析 CSS 语法,var(--primary) 对它来说就是一串无效字符。浏览器不会报错,而是静默 fallback 到 #000000(黑色)或完全透明。真正能用的只有已计算完毕的颜色值:"#3b82f6"、"rgb(59, 130, 246)"、"LightGreen"(注意大小写,"lightgreen" ❌)。HSL 函数、空格分隔色名、带单位的数字(如 --size: 16px)也全都不认。
getComputedStyle().getPropertyValue() 必须这么用
必须走 DOM 桥接:先让浏览器把 CSS 变量算出来,再把结果字符串喂给 Canvas。关键细节如下:
- 读根变量(全局)必须用
document.documentElement,不是document.body或随便一个元素 - 必须调用
.getPropertyValue('--primary'),不能写成.--primary(语法错误)或.style.getPropertyValue()(只读内联样式) - 返回值是字符串,且可能含前导/尾随空格,务必加
.trim(),否则旧版 Safari 会失败 - 如果变量定义在某个组件容器上(比如
.chart-container),就得传那个元素,而不是document.documentElement
主题切换后 Canvas 颜色没变?问题不在读取,在重绘
很多人只改了 CSS 变量,却忘了触发 Canvas 重绘——颜色值缓存对了,但图形还卡在旧状态。真实痛点是:
- 仅更新 CSS 变量不会自动调用
ctx.clearRect()和重绘逻辑 - 监听
prefers-color-scheme改变时,要同步更新颜色缓存 + 主动重绘整帧 - 若用
ResizeObserver响应尺寸变化,别在回调里反复调用getComputedStyle——提前缓存好primaryColor等值 - Flex 容器中 Canvas 尺寸缩放与颜色同步不同步,会导致图糊或错色;
canvas.width/canvas.height和canvas.style.width/canvas.style.height必须协同更新
rgba() 和系统色名在 Canvas 中的坑
rgba(100, 150, 200, 0.6) 能直接赋给 ctx.fillStyle,但效果和 CSS 不同:Canvas 中 alpha 控制的是本次绘制的“覆盖强度”,连续两次填充同一区域会叠加变暗;而 CSS 是合成结果。系统色名如 CanvasText 更危险:
立即学习“前端免费学习笔记(深入)”;
-
ctx.fillStyle = "CanvasText"在 Windows/macOS/不同深色模式下行为不一致,且切换主题后 Canvas 不会自动更新 - 不要依赖它做主题适配,改用明确的 CSS 变量 + 主动监听
matchMedia("(prefers-color-scheme: dark)") - 高频率绘制(如
requestAnimationFrame)中禁止每次都调用getComputedStyle,它会触发强制同步布局,卡顿明显
真正麻烦的不是怎么取值,而是颜色空间和绘图模型差异——Canvas 只认 sRGB,所有绘制都是位图叠加;CSS 变量背后可能是 display-p3、oklab 或自定义色彩空间。一旦涉及色域转换,结果就不可控。别指望“一致”是默认行为,得自己对齐。


















