Canvas 2D 不支持 CSS 变量,ctx.fillStyle = "var(--primary-color)" 会静默回退为黑色;需用 getComputedStyle(root).getPropertyValue('--primary-color').trim() 获取计算后的颜色值并缓存使用。

为什么 ctx.fillStyle = "var(--primary-color)" 会画出黑色
Canvas 2D 上下文根本不解析 CSS 语法,var(--primary-color) 对它来说就是一串无意义字符。浏览器不会报错,而是静默 fallback 到默认的 #000000(黑色)或完全透明——这不是 bug,是设计限制。
真正起作用的只有已计算完毕的颜色值:"#3b82f6"、"rgb(59, 130, 246)"、"LightGreen"(注意大小写,"lightgreen" ❌)。HSL 函数、空格分隔色名、带单位的数字(如 --size: 16px)也全都不认。
用 getComputedStyle().getPropertyValue() 正确读取变量值
必须走 DOM 桥接:先让浏览器把 CSS 变量算出来,再把结果字符串喂给 Canvas。
- 读根变量(全局):用
document.documentElement,不是document.body或随便一个元素 - 必须调用
.getPropertyValue('--primary-color'),不能写成.--primary-color(语法错误)或.style.getPropertyValue()(只读内联样式) - 返回值是字符串,且可能含前导/尾随空格,务必加
.trim(),否则旧版 Safari 会失败 - 如果变量定义在某个组件容器上(比如
.chart-container),就得传那个元素,而不是document.documentElement
Canvas 颜色同步的最小可行代码
下面这段代码能稳定拿到颜色并绘图,不依赖框架、不触发重排:
立即学习“前端免费学习笔记(深入)”;
const root = document.documentElement;
const color = getComputedStyle(root).getPropertyValue('--accent').trim();
if (color) {
ctx.fillStyle = color;
ctx.fillRect(10, 10, 100, 100);
} else {
ctx.fillStyle = '#3b82f6'; // 兜底色,避免静默失败
}
注意:不要在 requestAnimationFrame 或绘制循环里反复调用 getComputedStyle——它可能强制同步布局。建议在主题切换或初始化时缓存一次,后续直接用变量。
和 Flex 容器尺寸问题叠加时的坑
当 Canvas 放在 Flex 布局中,又同时要同步 CSS 颜色,两个问题会互相干扰:
- 只改
canvas.style.width/canvas.style.height是 CSS 缩放,不影响绘图分辨率,颜色即使对了图形也会糊 - 只更新
canvas.width/canvas.height而不重绘,上次的内容会残留或消失 - ResizeObserver 回调里读
getComputedStyle没问题,但别在回调里重复获取同一变量——缓存它 - 如果父 flex-item 是
display: none,getBoundingClientRect()可能返回 0,此时getComputedStyle仍可读取颜色,但尺寸逻辑需单独处理
颜色同步本身很简单,难的是把它嵌进响应式、动态主题、Flex 布局交织的真实场景里——变量值、画布尺寸、重绘时机,三者必须严格对齐,漏掉任一环都会表现为“颜色没变”或“图形错位”。


















