如何解决Canvas中Fontello图标显示为空方块的问题?
问题描述
尝试在Canvas中使用自定义Fontello字体导出图标为PNG,但无论使用哪种字符编码写法,都只显示空方块⎕。字体已在文档中正确加载,在DOM元素中能正常渲染,但Canvas绘制始终失败。
原始Canvas代码
ctx.font = `30px fontello`; ctx.fillText('\ue804', canvas.width / 2, canvas.height / 2); const image = canvas.toDataURL('image/png');
DOM测试可行代码
const span = document.createElement('span'); span.style.fontFamily = 'fontello' span.innerHTML = '' document.body.appendChild(span)
尝试过的无效写法
ctx.font = `30px "fontello"`; ctx.fillText('\\ue804', canvas.width / 2, canvas.height / 2); ctx.fillText('\uE804', canvas.width / 2, canvas.height / 2); ctx.fillText('', canvas.width / 2, canvas.height / 2); ctx.fillText('', canvas.width / 2, canvas.height / 2);
完整代码片段
JavaScript
const canvas = document.createElement('canvas'); canvas.width = 30; canvas.height = 30; const ctx = canvas.getContext('2d'); const circleStrokeColor = filter.filter_color.polyline; const circleFillColor = filter.filter_color.polygon; const circleRadius = Math.min(canvas.width, canvas.height) / 2 - 1; ctx.strokeStyle = this.hexToRgb(circleStrokeColor); ctx.fillStyle = this.hexToRgb(circleFillColor); ctx.beginPath(); ctx.arc(canvas.width / 2, canvas.height / 2, circleRadius, 0, 2 * Math.PI); ctx.fill(); ctx.lineWidth = 1; ctx.stroke(); ctx.fillStyle = this.hexToRgb(circleStrokeColor); ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.font = `30px fontello`; ctx.fillText('\ue804', canvas.width / 2, canvas.height / 2); const image = canvas.toDataURL('image/png'); console.log(image) return image
CSS
@font-face { font-family: 'fontello'; src: url('../font/fontello.eot?41849995'); src: url('../font/fontello.eot?41849995#iefix') format('embedded-opentype'), url('../font/fontello.woff2?41849995') format('woff2'), url('../font/fontello.woff?41849995') format('woff'), url('../font/fontello.ttf?41849995') format('truetype'), url('../font/fontello.svg?41849995#fontello') format('svg'); font-weight: normal; font-style: normal; } /* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */ /* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */ /* @media screen and (-webkit-min-device-pixel-ratio:0) { @font-face { font-family: 'fontello'; src: url('../font/fontello.svg?41849995#fontello') format('svg'); } } */ [class^="icon-"]:before, [class*=" icon-"]:before { font-family: "fontello"; font-style: normal; font-weight: normal; speak: never; display: inline-block; text-decoration: inherit; width: 1em; margin-right: .2em; text-align: center; /* opacity: .8; */ /* For safety - reset parent styles, that can break glyph codes*/ font-variant: normal; text-transform: none; /* fix buttons height, for twitter bootstrap */ line-height: 1em; /* Animation center compensation - margins should be symmetric */ /* remove if not needed */ margin-left: .2em; /* you can be more comfortable with increased icons size */ /* font-size: 120%; */ /* Font smoothing. That was taken from TWBS */ -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; /* Uncomment for 3D effect */ /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */ } .icon-gebouwen:before { content: '\e800'; } /* '' */ .icon-groen:before { content: '\e801'; } /* '' */ .icon-kabels-leidingen:before { content: '\e802'; } /* '' */ .icon-kunstwerken:before { content: '\e803'; } /* '' */ .icon-legenda:before { content: '\e804'; } /* '' */ .icon-meubilair:before { content: '\e805'; } /* '' */ .icon-riolering:before { content: '\e806'; } /* '' */ .icon-rioolgemalen:before { content: '\e807'; } /* '' */ .icon-speeltoestellen:before { content: '\e808'; } /* '' */ .icon-spoor-masten:before { content: '\e809'; } /* '' */ .icon-sport:before { content: '\e80a'; } /* '' */ .icon-verhardingen:before { content: '\e80b'; } /* '' */ .icon-verlichting:before { content: '\e80c'; } /* '' */ .icon-vri:before { content: '\e80d'; } /* '' */ .icon-water:before { content: '\e80e'; } /* '' */
解决建议
1. 等待字体完全加载后再绘制Canvas
Canvas绘制文字时,字体必须完成加载,否则会回退到默认字体导致方块。使用FontFace API显式控制加载流程:
const font = new FontFace('fontello', 'url("../font/fontello.ttf?41849995")'); font.load().then(() => { document.fonts.add(font); drawCanvasIcon(); // 字体加载完成后执行绘制 }); function drawCanvasIcon() { const canvas = document.createElement('canvas'); canvas.width = 30; canvas.height = 30; const ctx = canvas.getContext('2d'); // ... 保留原有的圆形绘制代码 ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.font = `20px fontello`; // 调整字体大小适配画布 ctx.fillText('\ue804', canvas.width / 2, canvas.height / 2); const image = canvas.toDataURL('image/png'); console.log(image); return image; }
2. 调整字体格式加载优先级
部分浏览器对WOFF2格式在Canvas中的支持存在延迟,调整@font-face的src顺序,优先加载TTF格式:
@font-face { font-family: 'fontello'; src: url('../font/fontello.ttf?41849995') format('truetype'), url('../font/fontello.eot?41849995') format('embedded-opentype'), url('../font/fontello.woff2?41849995') format('woff2'), url('../font/fontello.woff?41849995') format('woff'), url('../font/fontello.svg?41849995#fontello') format('svg'); font-weight: normal; font-style: normal; }
3. 修正字体大小与画布尺寸的匹配问题
你的Canvas尺寸为30x30,设置30px字体大小会导致图标超出画布范围,视觉上表现为空方块。缩小字体大小或增大画布:
ctx.font = `20px fontello`; // 缩小字体适配30x30画布 // 或者增大画布尺寸 canvas.width = 40; canvas.height = 40; ctx.font = `30px fontello`;
4. 确认字符编码的正确性
- 仅使用纯Unicode转义符:
'\ue804'是正确写法,无需额外转义 - 不要使用HTML实体(如
),fillText不解析HTML,会直接渲染实体文本
内容的提问来源于stack exchange,提问作者Delyan Ninov
相关产品推荐
相关产品推荐

