用 Canvas 在浏览器里生成封面图:从渐变背景到圆角矩形的完整实践
一、为什么要用代码生成封面图
写技术文章、做课程封面、给项目生成预览图时,经常需要一张尺寸固定、风格统一的图片。手工用设计工具做,每换一次文字就要重做;用图片素材站找,又容易撞图或者有授权问题。
其实浏览器自带的能力就够用了:Canvas API 可以在几十行代码里画出一张符合尺寸要求、内容完全自定义的图片,而且不依赖任何第三方库。
二、基本骨架
核心就三步:创建画布、绘制内容、导出成图片。
const canvas = document.createElement('canvas');
canvas.width = 800;
canvas.height = 450;
const ctx = canvas.getContext('2d');
// ……在这里绘制
const dataUrl = canvas.toDataURL('image/png');
导出这一步要注意:toDataURL 返回的是 base64 字符串,可以直接塞进 img 的 src,也可以转成 Blob 再上传。
三、画出需要的元素
1. 渐变背景。用 createLinearGradient 做斜向渐变,比纯色更有层次:
const g = ctx.createLinearGradient(0, 0, 800, 450);
g.addColorStop(0, '#0b1b33');
g.addColorStop(0.55, '#123055');
g.addColorStop(1, '#0a1626');
ctx.fillStyle = g;
ctx.fillRect(0, 0, 800, 450);
2. 网格线。用循环画等距线条,透明度调低,作为装饰不抢主体:
ctx.strokeStyle = 'rgba(90,160,255,0.14)';
ctx.lineWidth = 1;
for (let x = 0; x <= 800; x += 40) {
ctx.beginPath();
ctx.moveTo(x, 0);
ctx.lineTo(x, 450);
ctx.stroke();
}
3. 圆角矩形。现代浏览器支持 ctx.roundRect,但为了兼容旧环境,建议做一次能力检测:
ctx.beginPath();
if (ctx.roundRect) {
ctx.roundRect(x, y, w, h, 10);
} else {
ctx.rect(x, y, w, h);
}
ctx.fill();
ctx.stroke();
4. 文字。字体要显式指定,否则不同系统渲染差异很大。中文字体建议带上回退栈:
ctx.font = 'bold 40px "Microsoft YaHei", "PingFang SC", sans-serif';
ctx.fillStyle = '#ffffff';
ctx.fillText('标题文字', 570, 180);
四、几个容易踩的坑
坑一:导出后图片模糊。Canvas 默认按 CSS 像素绘制,在高分屏或需要放大显示时会糊。解决办法是按 devicePixelRatio 放大画布尺寸,再用 ctx.scale 缩放坐标系:
const dpr = window.devicePixelRatio || 1;
canvas.width = 800 * dpr;
canvas.height = 450 * dpr;
canvas.style.width = '800px';
canvas.style.height = '450px';
ctx.scale(dpr, dpr);
坑二:上传平台有最小尺寸要求。很多平台对封面有下限,比如要求大于等于 240×135。建议一开始就按 16:9 的较大尺寸(如 800×450)生成,缩小时不会失真。
坑三:toDataURL 体积偏大。PNG 无损但体积大,纯色较多的图可以用 toBlob 指定 jpeg 和压缩质量:
canvas.toBlob((blob) => {
// blob 可直接用 FormData 上传
}, 'image/jpeg', 0.88);
坑四:字体加载时机。如果用到自定义字体,要在 document.fonts.ready 之后再绘制,否则会回退到默认字体。
五、完整可运行示例
把下面这段直接贴进浏览器控制台,就能得到一张 800×450 的技术风封面:
function makeCover(title, subtitle) {
const W = 800, H = 450;
const c = document.createElement('canvas');
c.width = W; c.height = H;
const ctx = c.getContext('2d');
const g = ctx.createLinearGradient(0, 0, W, H);
g.addColorStop(0, '#0b1b33');
g.addColorStop(1, '#0a1626');
ctx.fillStyle = g;
ctx.fillRect(0, 0, W, H);
ctx.strokeStyle = 'rgba(90,160,255,0.14)';
for (let x = 0; x <= W; x += 40) {
ctx.beginPath(); ctx.moveTo(x, 0); ctx.lineTo(x, H); ctx.stroke();
}
ctx.fillStyle = '#2f7cff';
ctx.fillRect(0, 0, 10, H);
ctx.fillStyle = '#ffffff';
ctx.font = 'bold 40px "Microsoft YaHei", sans-serif';
ctx.fillText(title, 60, 200);
ctx.fillStyle = '#8fc3ff';
ctx.font = '20px "Microsoft YaHei", sans-serif';
ctx.fillText(subtitle, 60, 250);
return c.toDataURL('image/png');
}
console.log(makeCover('前端排障实录', 'Canvas 生成封面'));
六、小结
Canvas 生成图片的价值不在于替代设计工具,而在于把"尺寸固定、内容可变"的图变成可编程的产物。批量生成、动态文字、CI 流程里自动出图,这些场景用代码远比手工高效。
- 点赞
- 收藏
- 关注作者
评论(0)