一 🎨 核心文本属性
Canvas 的文本样式和对齐由以下几个关键属性控制,它们都作用于 Canvas 的 2D 渲染上下文(通常简称为 ctx)。
1. font 属性
这是设置文本字体样式的核心属性,其语法与 CSS 的 font 属性完全相同。
- 默认值:
10px sans-serif - 语法:
ctx.font = "font-style font-variant font-weight font-size font-family";
| 属性分量 | 描述 | 常用值 |
|---|---|---|
font-style | 字体样式 | normal (正常), italic (斜体), oblique (倾斜体) |
font-variant | 字体变体 | normal (正常), small-caps (小型大写字母) |
font-weight | 字体粗细 | normal (正常), bold (粗体), 100 到 900 的数字 |
font-size | 字体大小 | 必须包含单位,如 16px, 2em |
font-family | 字体族 | Arial, "Microsoft YaHei", sans-serif 等 |
示例:
ctx.font = "bold italic 24px Arial"; // 粗体、斜体、24像素、Arial字体
ctx.font = "30px 'Microsoft YaHei', sans-serif"; // 30像素,优先使用微软雅黑
正确的书写顺序必须遵循以下规则:
font-style → font-variant → font-weight → font-size → font-family
📝 顺序规则详解
-
font-style(字体样式) 例如italic(斜体) 或oblique(倾斜体)。 -
font-variant(字体变体) 例如small-caps(小型大写字母)。 -
font-weight(字体粗细) 例如bold(粗体) 或700。 -
font-size(字体大小) 例如16px或2em。这是第一个必须指定的属性。 -
font-family(字体族) 例如Arial或"Microsoft YaHei"。这是第二个必须指定的属性。
✅ 核心要点
font-size和font-family是必选项:如果缺少这两个值中的任何一个,整个font属性设置将不会生效。font-size必须在font-family之前:这两者的相对顺序不能颠倒。- 前三项顺序可互换:
font-style、font-variant和font-weight这三项之间的顺序可以任意调换,并且它们都是可选项,可以省略。
💻 代码示例
以下是一些正确和错误的写法示例:
// ✅ 正确写法
ctx.font = "italic small-caps bold 24px Arial"; // 完全符合顺序
ctx.font = "bold italic 24px Arial"; // 省略了 font-variant
ctx.font = "24px 'Microsoft YaHei', sans-serif"; // 只写了两个必选项
// ❌ 错误写法
ctx.font = "24px bold Arial"; // font-weight 写在了 font-size 后面
ctx.font = "Arial 24px bold"; // font-family 写在了 font-size 前面
ctx.font = "bold Arial"; // 缺少了必选项 font-size
2. textAlign 属性
此属性用于设置文本的水平对齐方式。对齐的基准点是你在绘制文本时指定的 x 坐标。
- 默认值:
start - 可选值:
start: 默认值。文本从起点开始绘制(在从左到右的语言环境中,效果同left)。end: 文本终点对齐起点(在从左到右的语言环境中,效果同right)。left: 文本左对齐。right: 文本右对齐。center: 文本中心点对齐起点。
示例:
ctx.textAlign = "center"; // 文本将以x坐标为中心进行水平居中
ctx.fillText("居中的文本", canvas.width / 2, 100);
3. textBaseline 属性
此属性用于设置文本的垂直对齐方式,即文本的基线。对齐的基准点是你在绘制文本时指定的 y 坐标。
- 默认值:
alphabetic - 可选值:
top: 文本基线在文本块的顶部。hanging: 文本基线是悬挂基线(常用于印度系文字)。middle: 文本基线在文本块的中间。alphabetic: 文本基线是标准的字母基线(默认值,适用于大多数拉丁字母)。ideographic: 文本基线是表意字基线(适用于中文、日文等)。bottom: 文本基线在文本块的底部。
示例:
ctx.textBaseline = "middle"; // 文本将以y坐标为中心进行垂直居中
ctx.fillText("垂直居中的文本", 100, canvas.height / 2);
4. direction 属性
此属性用于设置文本的书写方向。
- 默认值:
inherit - 可选值:
ltr: 从左到右 (Left-to-Right)。rtl: 从右到左 (Right-to-Left)。inherit: 继承父元素的设置。
- 对于纯英文 'hello font',ltr 和 rtl 看起来是一样的
- 使用希伯来语/阿拉伯语文字,或混合文本时,效果才明显:
- ltr: 文本从左到右排列
- rtl: 文本从右到左排列(起始位置会变化)
二 ✍️ 核心文本方法
设置好属性后,需要使用以下方法来实际绘制文本。
1. fillText() 方法
在指定坐标 (x, y) 处绘制实心填充的文本。
- 语法:
ctx.fillText(text, x, y [, maxWidth]); - 参数:
text: 要绘制的文本字符串。x: 文本起始点的 x 轴坐标。y: 文本起始点的 y 轴坐标。maxWidth(可选): 允许的最大文本宽度。如果文本宽度超过此值,浏览器会自动缩放字体以适应宽度。
2. strokeText() 方法
在指定坐标 (x, y) 处绘制文本的轮廓(描边)。
- 语法:
ctx.strokeText(text, x, y [, maxWidth]); - 参数: 与
fillText相同。
3. measureText() 方法
用于测量文本的宽度,返回一个 TextMetrics 对象。这在需要动态计算文本位置时非常有用。
- 语法:
ctx.measureText(text) - 返回值: 一个包含文本宽度等信息的
TextMetrics对象。你可以通过.width属性获取文本的宽度(以像素为单位)。
示例:
const text = "Hello Canvas";
const metrics = ctx.measureText(text);
console.log(`文本宽度为: ${metrics.width}px`);
🧩 综合示例
下面是一个完整的示例,展示了如何结合使用这些属性和方法在 Canvas 上绘制一个水平和垂直都居中的文本。
<canvas id="myCanvas" width="400" height="200" style="border:1px solid #ccc;"></canvas>
<script>
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
// 1. 设置文本样式
ctx.font = 'bold 40px "Microsoft YaHei", sans-serif';
ctx.fillStyle = '#336699'; // 设置填充颜色
// 2. 设置对齐方式
ctx.textAlign = 'center'; // 水平居中
ctx.textBaseline = 'middle'; // 垂直居中
// 3. 计算画布中心点坐标
const x = canvas.width / 2;
const y = canvas.height / 2;
// 4. 绘制实心文本
ctx.fillText('Canvas 文本', x, y);
// 5. 绘制描边文本
ctx.strokeStyle = '#ffcc00';
ctx.lineWidth = 1;
ctx.strokeText('Canvas 文本', x, y);
</script>
三 源码案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
body {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<canvas id="myCanvas"></canvas>
<script>
const canvas = document.getElementById('myCanvas');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
// 1.textAlign 属性
const ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.moveTo(250, 50);
ctx.lineTo(250, 350);
ctx.strokeStyle = 'skyblue';
ctx.stroke();
const textAligns = ['start', 'end', 'left', 'right', 'center'];
for (let i = 0; i < textAligns.length; i++) {
ctx.textAlign = textAligns[i];
ctx.font = '20px Arial';
ctx.fillText('textAlign: ' + textAligns[i], 250, 100 + i * 50);
}
// 2.textBaseline 属性
ctx.beginPath();
ctx.moveTo(550, 200);
ctx.lineTo(1450, 200);
ctx.strokeStyle = 'red';
ctx.stroke();
const textBaselines = ['top', 'hanging', 'middle', 'alphabetic', 'ideographic', 'bottom'];
for (let i = 0; i < textBaselines.length; i++) {
ctx.textBaseline = textBaselines[i];
ctx.font = '20px Arial';
ctx.fillText(textBaselines[i], 600 + i*150, 200);
}
//
ctx.beginPath();
ctx.textAlign = 'left'
ctx.textBaseline = 'alphabetic'
ctx.direction = 'ltr'
ctx.font = "italic small-caps bold 24px Arial"; // 完全符合顺序
ctx.fillText('hello font', 50, 50);
ctx.lineWidth = 1;
ctx.strokeStyle = '#eee';
ctx.strokeText('hello font', 50, 50);
// 3.direction 属性演示 - 需要 RTL 文字或配合 textAlign 才能看到效果
ctx.beginPath();
ctx.textAlign = 'left';
ctx.textBaseline = 'alphabetic';
// ltr (默认)
ctx.direction = 'ltr';
ctx.font = "24px Arial";
ctx.fillText('LTR: שלום עולם (Shalom)', 50, 550);
// rtl - 文字会从右向左排列
ctx.direction = 'rtl';
ctx.fillText('RTL: שלום עולם (Shalom)', 50, 600);
// 混合文本对比
ctx.direction = 'ltr';
ctx.fillText('LTR: Hello 世界', 50, 650);
ctx.direction = 'rtl';
ctx.fillText('RTL: Hello 世界', 50, 700);
</script>
</body>
</html>