前端打工人必看:用 measureText 精准拿捏 Canvas 文字宽度(附避

canvas测量文字长度(measureText) 如何使用canvas测量一串文字的长度呢?canvas中提供了一个方法measureText,他的测量是非常准确的。 提醒: 在制作这个示例的时候,出现了顺序上的错误,将ctx.font放到了ctx.measureText()的后面,致使测量的数据长度值不正确。 `正确节奏是 先设定字体大小,然后再测量长度`。 阅读详情

前端打工人必看:用 measureText 精准拿捏 Canvas 文字宽度(附避坑指南)

为啥画个文字还要量尺寸?别急,等你被 UI 设计师追着改对齐就懂了

前阵子公司做活动页,产品经理甩过来一张设计稿:「就按这个来,文字要居中,气泡要自适应,还要支持换行。」我瞅了一眼,心想这不就是画个 Canvas 吗,分分钟搞定。结果真正上手才发现,文字这玩意儿在 Canvas 里就是个熊孩子,表面上乖乖站着,实际上到处乱跑。

你以为 ctx.fillText('你好世界', x, y) 就完事了?天真!文字压根不听你的指挥,左边多出来一截,右边又空着一大块,设计师看了直摇头:「这不对齐啊,重做!」那一刻我才深刻体会到,Canvas 里画文字,不量尺寸就是给自己挖坑。

Canvas 里文字不是你想放就能放

在 DOM 世界里,文字天生带盒子。div 有 clientWidth,span 有 getBoundingClientRect(),你随时能知道它占多大地方。可 Canvas 是一片白纸,文字画上去就像泼出去的水,浏览器不会告诉你「这段字 120px 宽、28px 高」。于是你只能凭感觉盲调 x、y,结果一跑真机,字体渲染差异直接教你做人。

更惨的是,一旦涉及多语言、emoji、动态字号,翻车率呈指数级上升。你以为居中就是 (画布宽 - 文字宽) / 2?实际上文字宽到底是多少,鬼知道!直到我遇见 measureText,才发现原来浏览器偷偷给咱们留了一把尺子,只是很多人不知道咋用。

measureText 是啥玩意儿

一句话:这是 Canvas 2D 上下文自带的「文字卷尺」,调用一次返回一个对象,里面装着这段文字在当前字体下的各种尺寸信息。零依赖、零配置,浏览器原生支持,从 IE9 到现在全员在线。

const ctx = document.createElement('canvas').getContext('2d');
ctx.font = '16px sans-serif';
const measure = ctx.measureText('hello 世界');
console.log(measure.width); // 82.34  单位是 px,精确到小数点后两位

看到那个 width 没?它就是这段文字在画布上的横向占地面积。有了它,你就能算出居中位置、换行断点、气泡拉伸长度,再也不用瞪眼猜。

这 API 到底怎么用

最简姿势一行代码:

const textWidth = ctx.measureText('前端真好玩').width;

但真实项目里,字体、字号、字重、行高一个都不能少。先把 font 属性写全,再测:

ctx.font = 'bold 24px/1.5 "PingFang SC", "Helvetica Neue", sans-serif';
const m = ctx.measureText('iPhone 14 Pro 只要 9999 元');
console.log(m.width); // 261.45

注意:

  1. font 的语法和 CSS 完全一致,顺序不能乱。
  2. 如果字体列表里有自定义字体,确保已经加载完成,否则拿到的是 fallback 字体的宽度。
  3. 测量之前一定要 ctx.font = ... 先赋值,否则默认是 10px sans-serif,数据直接跑偏。

别被 width 迷了眼

很多人以为 measureText 就返回一个数字,其实它是一个对象,除了 width 还有一堆冷门属性,关键时刻能救命:

const metrics = ctx.measureText('中文 ABC');
console.log(metrics);
/*
{
  width: 104.67,
  actualBoundingBoxLeft: -3,     // 字形最左边相对于文本原点的偏移,负值表示向左探出
  actualBoundingBoxRight: 101,   // 字形最右边相对于文本原点的偏移
  actualBoundingBoxAscent: 22,   // 字形最高点到基线的距离
  actualBoundingBoxDescent: 6,   // 字形最低点到基线的距离(基线以下为正)
  fontBoundingBoxAscent: 27,    // 字体设计时 ascent,不受具体字形影响
  fontBoundingBoxDescent: 8,
  emHeightAscent: 21,
  emHeightDescent: 5
}
*/

做垂直居中时,如果你只按 fontSize/2 去算,往往偏上或偏下。正确姿势是用 actualBoundingBoxAscent 和 actualBoundingBoxDescent 算出真实高度:

function drawTextVerticalCenter(ctx, text, x, centerY) {
  const m = ctx.measureText(text);
  const realHeight = m.actualBoundingBoxAscent + m.actualBoundingBoxDescent;
  const baselineY = centerY - (realHeight / 2) + m.actualBoundingBoxAscent;
  ctx.fillText(text, x, baselineY);
}

同理,如果你要给文字加背景色块,用 actualBoundingBoxLeft/Right 就能避免「左右留白不一致」的尴尬。

字体一换,世界崩塌

系统字体通常秒加载,但项目里不用个自定义字体都不好意思说自己是做品牌的。于是你开开心心 @font-face 引入「阿里巴巴普惠体」,结果 measureText 拿到的宽度永远比真实渲染窄一截,why?

因为 measureText 测的是「当前已生效」字体。自定义字体文件还没下载完,浏览器会用 fallback 字体先顶着,你这时候测,拿到的就是 fallback 的宽度。等字体加载完再测,数据才对得上。所以记住两条铁律:

  1. 等字体就绪再测:
document.fonts.ready.then(() => {
  ctx.font = '20px "AlibabaPuHuiTi"';
  const w = ctx.measureText('双 11 爆款清单').width;
  drawPoster(w);
});
  1. 如果字体可能动态切换,把测量逻辑包在 document.fonts.load() 里:
await document.fonts.load('20px "AlibabaPuHuiTi"');
ctx.font = '20px "AlibabaPuHuiTi"';
// 现在测,稳了

高 DPI 屏幕下的玄学问题

Retina 屏上,Canvas 默认被浏览器放大 2 倍绘制,结果文字模糊得像毛玻璃,测量值也跟着飘。解决方案两步走:

  1. 按 devicePixelRatio 放大画布实际尺寸:
const dpr = window.devicePixelRatio || 1;
const canvas = document.querySelector('#myCanvas');
const rect = canvas.getBoundingClientRect();
canvas.width = rect.width * dpr;
canvas.height = rect.height * dpr;
ctx.scale(dpr, dpr);
  1. 所有坐标、尺寸用 CSS 像素做单位,放大交给 scale,measureText 返回的宽度已经是 CSS 像素,无需再除 dpr。
    一顿操作后,文字立马高清,测量值和渲染像素完美对齐,设计师再也挑不出刺。

性能别乱造

有人担心「频繁调 measureText 会不会卡?」我专门跑了个测试:MacBook M1 上循环 10 万次测一段 20 个字符的字符串,耗时 20ms 左右,平均每次 0.2μs。结论:它比你想象中快得多。但别作死:

  • 不要在 requestAnimationFrame 里每帧测几十段长文,再快也扛不住。
  • 缓存!同样的文字、同样的字体,测一次存起来,用 Map 或对象做键值映射:
const measureCache = new Map();
function cachedMeasure(ctx, text, font) {
  const key = `${font}||${text}`;
  if (measureCache.has(key)) return measureCache.get(key);
  const oldFont = ctx.font;
  ctx.font = font;
  const m = ctx.measureText(text);
  ctx.font = oldFont;
  measureCache.set(key, m);
  return m;
}

实战场景拉满

动态生成海报时自动换行

需求:用户昵称最长 20 字符,超出自动换行,气泡宽度固定 300px。
思路:逐个字符累加宽度,超了就在上一个安全断点截断。

function breakLines(ctx, text, maxWidth) {
  const chars = Array.from(text); // 正确处理 emoji
  let line = '';
  let lines = [];
  for (let c of chars) {
    const testLine = line + c;
    const { width } = ctx.measureText(testLine);
    if (width > maxWidth && line !== '') {
      lines.push(line);
      line = c;
    } else {
      line = testLine;
    }
  }
  lines.push(line);
  return lines;
}

// 使用
ctx.font = '22px "PingFang SC"';
const nickname = '超级无敌暴龙战士🦖';
const rows = breakLines(ctx, nickname, 300);
rows.forEach((row, i) => {
  ctx.fillText(row, 50, 100 + i * 30);
});

聊天气泡文字自适应宽度

气泡左右留 20px padding,上下 12px,圆角 16px。先测文字宽,再画路径:

function drawBubble(ctx, text, x, y) {
  const padding = 20;
  const radius = 16;
  const m = ctx.measureText(text);
  const w = m.width + padding * 2;
  const h = 36; // 固定高度,懒得算行高
  roundRect(ctx, x, y, w, h, radius);
  ctx.fillStyle = '#95EC69';
  ctx.fill();
  ctx.fillStyle = '#000';
  ctx.fillText(text, x + padding, y + 24);
}

function roundRect(ctx, x, y, w, h, r) {
  ctx.beginPath();
  ctx.moveTo(x + r, y);
  ctx.arcTo(x + w, y, x + w, y + h, r);
  ctx.arcTo(x + w, y + h, x, y + h, r);
  ctx.arcTo(x, y + h, x, y, r);
  ctx.arcTo(x, y, x + w, y, r);
  ctx.closePath();
}

数据可视化里标签防重叠

柱状图顶部标签,如果两根柱子太近,文字会叠在一起。先测宽度,再判断是否会相交:

const labels = [
  { text: '1.2w', x: 120 },
  { text: '1.3w', x: 140 }
];
const margin = 8;
for (let i = 1; i < labels.length; i++) {
  const prev = labels[i - 1];
  const curr = labels[i];
  const prevWidth = ctx.measureText(prev.text).width;
  const currWidth = ctx.measureText(curr.text).width;
  const prevRight = prev.x + prevWidth / 2;
  const currLeft = curr.x - currWidth / 2;
  if (prevRight + margin > currLeft) {
    // 会重叠,把 curr 标签往右挤
    curr.x += (prevRight + margin - currLeft);
  }
}

输入框字数实时进度条(带 emoji 特殊处理)

emoji 在 JS 里长度是 2,但渲染宽度不一定等于两个英文字母。用 measureText 才能反映真实像素:

input.addEventListener('input', e => {
  const val = e.target.value;
  const m = offscreenCtx.measureText(val);
  const ratio = Math.min(m.width / maxWidth, 1);
  progressBar.style.transform = `scaleX(${ratio})`;
});

测不准?先查这三件事

  1. 字体真的加载完了吗?
    别忘了 document.fonts.ready,否则永远是 fallback 宽度。
  2. Canvas 上下文的 font 属性写全没?
    大小、字重、族名必须和 fillText 时完全一致,差一个空格都可能翻车。
  3. 测的是中文还是 emoji?
    某些组合 emoji 宽度返回 0 不是 bug,是字体里根本没这个字形,浏览器用图片替代,测量拿不到尺寸。真要高精度,可用 span.getBoundingClientRect() 兜底:
function measureTextDomFallback(text, font) {
  const span = document.createElement('span');
  span.style.font = font;
  span.style.whiteSpace = 'pre';
  span.textContent = text;
  document.body.appendChild(span);
  const rect = span.getBoundingClientRect();
  document.body.removeChild(span);
  return { width: rect.width, height: rect.height };
}

骚操作开发技巧

  • 缓存测量结果,别重复造轮子,前面代码已给模板。
  • 用离屏 Canvas 预测文字尺寸,主屏丝滑如德芙:
const offscreen = new OffscreenCanvas(1, 1);
const offCtx = offscreen.getContext('2d');
// 所有测量走 offCtx,不影响主画布
  • 遇到极端混合语言(中日韩 + emoji + 特殊符号),measureText 也头疼,可以「分段测量」:正则把 emoji、英文、中文切开,各自测宽再求和,误差降到 1px 以内。

最后唠叨一句

measureText 不是万能的,但不用它,你的 Canvas 文字永远在「差不多」边缘疯狂试探。今天把压箱底的笔记都掏出来了,谁再被设计师吐槽文字对不齐,就把这篇文章甩给他:「兄弟,尺子给你,自己量!」

在这里插入图片描述

JS使用canvas中的measureText方法测量字体宽度示例 主要介绍了JS使用canvas中的measureText方法测量字体宽度,结合实例形式分析了canvas的measureText方法相关使用技巧,需要的朋友可以参考下 立即下载

相关推荐

三端口DC-DC变换器设计与光伏储能协同控制

三端口DC-DC变换器是面向分布式能源系统的关键功率变换拓扑,通过在光伏输入、储能电池与直流负载三个端口间实现动态能量分配,解决多源异步供电下的电压稳定与功率平衡问题。其核心原理基于双Boost半桥架构与双闭环协同控制,融合MPPT最大功率点跟踪与电池智能充放电管理,在保证30V高精度稳压(±0.5V)的同时,支持光伏主导供电与电池支撑供电的自动模式切换。该技术显著提升光储系统能量利用率与供电连续性,广泛应用于微电网、便携式交直流电源及离网型光储一体机等场景,是构建柔性直流配电与智能能源管理的基础硬件单元。

weixin_36431814的博客 140

【文本】HTML5 Canvas文本度量measureText()

介绍 在canvas绘图环境中,measureText()方法可以度量字体的宽度。measureText()方法返回了一个包含width属性的TextMetrics对象,后期我们会使用这个方法实现文本编辑器。 measureText()方法的用法 方法 描述了 TextMetrics measureText(DOMString text) 返回一个TextMetric...

苏一恒 4081

quartus 13.1常见报错解决方法

在使用quartus中会遇到很多由于安装或设置不规范造成的错误。我就目前我遇到的一些错误以及我的解决方法分享给大家,这个文章将会持续更新,如果读者有遇到软件中错误无法解决的问题,也欢迎在评论区留言。 一、编译出现lience错误 在对设计的电路编译时,系统在程序运行3秒内即结束并报错,大概意思为现有的证书不支持编译。这个常见问题源自破解不成功,这里读者很有可能犯的错误是在使用破解器的时候没有区分x86(即32-bit)和x64软件破解器对应的文件夹。 如图所示有两种破解器,分别对应32位和64位的软件,大部

肥宅的博客 3万+

Canvas中measureText函数的应用

measureText()函数是Canvas API中一个十分有用的函数,它可以帮助我们实现文本的居中对齐和动态调整字体大小等功能。在使用时,我们需要注意它的返回值是一个TextMetrics对象,其中包含了文本的宽度信息。希望本文能够帮助大家更好地理解和使用measureText()函数。

欢迎光临~ 3213

深入解析set_clock_groups:异步时钟约束的最佳实践与陷阱规避

本文深入解析了FPGA/芯片设计中set_clock_groups命令在异步时钟约束中的核心作用与最佳实践。文章对比了同步时钟、异步时钟与不重叠时钟的区别,强调了正确使用set_clock_groups避免时序分析陷阱的重要性,并提供了与set_false_path的优先级差异分析及实战规避方法,帮助设计者确保时序收敛与电路可靠性。

weixin_29232121的博客 372

CTF---Web---文件包含---01

文章目录前言一、题目描述二、解题步骤1.查看源代码2.文件包含(/etc/passwd)3.解码总结 前言 题目分类: CTF—Web—文件包含 一、题目描述 题目:提示寻找passwd文件 二、解题步骤 1.查看源代码 提示所有图片存储路径是download.php?name=img, 此时name参数的存在就提示此题可能为“文件包含”。 2.文件包含(/etc/passwd) 两种查看方式: 2.1、访问view-source:http://192.168.87.180/download.php

qq_22160557的博客 1391

《canvas》之第5章 文本操作

canvas 文本操作

yxqq378287007的博客 1944

Podman修改镜像源教程(附最新docker镜像源)

Podman修改镜像源教程(附最新docker镜像源)

道长的博客 4140

HTML5 canvas 计算文字宽度的方法(measureText)

var c=document.getElementById("myCanvas"); var ctx=c.getContext("2d"); ctx.font="30px Arial"; var txt="Hello World" ctx.fillText("width:" + ctx.measureText(txt).width,10,50) ctx.fillText(txt,10,100);...

hnnd123的博客 1万+

ARM架构下Horizon Client安装全攻略:从依赖检查到环境变量配置

本文详细介绍了在ARM架构设备上安装VMware Horizon Client的全过程,包括依赖检查、软件包获取、系统部署和环境变量配置。特别针对华为鲲鹏等ARM平台,提供了从基础准备到性能优化的完整指南,帮助用户高效完成虚拟桌面客户端的部署与调优。

github5actions的博客 551

华为OD机试2025C卷 - CPU调度策略 (C++ & Python & JAVA & JS & GO)

华为OD机试 2025C卷 CPU调度策略,提供Java、C++、Python、Go、JavaScript源码实现,并提供完整思路讲解

qq_45776114的博客 1295

canvas的context.measureText

"在当前字体样式下的宽度,并将结果打印到控制台。使用该方法时,需要先获取到CanvasRenderingContext2D对象的引用,通常可以通过调用canvas.getContext(‘2d’)来获取。然后,可以使用该对象的measureText()方法来测量文本的宽度。context.measureText()是HTML5 Canvas中的一个方法,用于测量给定文本在画布上的宽度。注意:由于measureText()方法返回的是一个包含宽度信息的对象,因此需要使用.width属性来获取实际的宽度值。

weixin_44283589的博客 999

【OpenClaw企业级智能体实战】第10篇:医疗行业OpenClaw实战:病历自动书写、医保智能审核与患者随访管理(附HIPAA合规配置+完整代码)

医疗行业正面临“效率提升需求”与“合规监管红线”的双重矛盾:病历书写占据医生30%-50%工作时间,医保审核效率低下,患者随访工作量巨大,但医疗数据“不出域”“责任不转移”的要求又限制了AI落地。本文基于华为云、腾讯云安全规范及中关村科金、复旦大学附属中山医院等真实实践,拆解OpenClaw在医疗场景的五大核心应用(病历自动书写、医保智能审核、患者随访管理、科研文献综述、医学影像预处理),提供私有化部署架构、HIPAA合规配置模板、完整实操流程及可直接运行的代码。

专注于人工智能、软件开发、工控自动化、工厂数字化及智能化等领域,希望和大家共同进步! 438

JS测量文字的宽度px和高度px

如果单纯测量文字宽度px,比较常用的方法是使用canvas的context.measureText: function measureUseCanvas(fontSize, fontFamily, text) { var canvas = document.createElement("canvas"); var context = canvas.getContext(...

qq_34452824的博客 5218

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

js获取文字的宽度

通过canvas api 获取文字宽度。

阿臻 1194

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

js简单准确计算动态字符串宽度

最近在项目中遇到需要计算字符串宽度,根据动态的字符串宽度去做出超出宽度省略文字的效果,以下是我觉得比较简单方便的方法,记录一下: 1.定义计算字符串长度函数 function getTextWith(text, fontStyle) { var canvas = document.createElement('canvas') var context = canvas.getContext('2d') context.font = fontStyle || '16px' // 设置字体样式

weixin_47292253的博客 1703

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

javascript基础学习系列五百六十二:绘制文本

 textAlign:指定文本的对齐方式,可能的值包括"start"、“end”、“left”、“right"和。推荐使用"start"和"end”,不使用"left"和"right",因为前者无论在从左到右。文本底部,“hanging”、"alphabetic"和"ideographic"分别引用字体中特定的基准点。文本和图像混合也是常见的绘制需求,因此2D绘图上下文还提供了绘制文本的方法,即fillText()表示文本的左侧坐标,而"end"会让x 坐标在从左到右书写的语言中表示文本的右侧坐标。

m0_68635815的博客 453

canvas的measureText()方法

做一个小动画的时候遇到了个问题,就是在给文字应用渐变色的时候,不知怎么设置渐变色的区域。 渐变依赖于定义时的区域,超出这个区域只有纯色,而不是渐变色。 所以要取得文字的宽度。 查了资料得知,canvas有一个measureText()方法,它会返回一个TextMetrics对象,该对象只有一个width属性。 只需要把文本传入measureText()即可: var texts = '...

weixin_30892889的博客 623

Canvas 获取文本宽度使用ctx.measureText

【代码】Canvas 获取文本宽度使用ctx.measureText。

weixin_43923808的博客 930

基于measure实现的文本测量

hongxiaomeng的博客 702

[js高手之路] html5 canvas系列教程 - 文本样式(strokeText,fillText,measureText,textAlign,textBaseline)...

接着上文线条样式[js高手之路] html5 canvas系列教程 - 线条样式(lineWidth,lineCap,lineJoin,setLineDash)继续. canvas提供两种输出文本的方式: strokeText:描边文本 fillText:填充文本 fillStyle配合fillText使用,strokeStyle配合strokeText使用 strokeText用法: ...

weixin_34345560的博客 364

Paint类measureText与getTextBounds的区别

转载地址:http://stackoverflow.com/questions/7549182/android-paint-measuretext-vs-gettextbounds; 在使用Canvas绘制文字时,需要得到字符串的长度,Paint类内给了两个方法,measureText(),getTextBound(); 可是对于同于字符串两个方法得出来的值有些差别: get

流萤的博客 1万+

canvas-文字样式-measureText

canvas中使用measureText()方法 得到关于文字的尺寸信息(宽、高等)

weixin_54057363的博客 621

React Native Measure Text:精准测量文本尺寸的利器

React Native Measure Text:精准测量文本尺寸的利器 在移动应用开发中,文本的布局和尺寸计算是一个常见但又复杂的问题。特别是在使用React Native进行跨平台开发时,如何在不实际渲染文本的情况下准确测量其高度和宽度,成为了开发者们的一大挑战。为了解决这一问题,React Native Measure Text应运而生,它提供了一种高效、便捷的方式来测量文本的尺寸,极大地...

gitblog_00176的博客 1244

JS 实现计算字符串的实际宽度

JS 实现计算字符串的实际宽度

momo_mom177的博客 1353

1分钟学会如何用 JS 计算文本的宽度

在项目开发中,我们有时候需要计算文本的内容宽度,你是怎么做的呢?今天看到一篇关于此内容的简短文章在此分享给大家。方法一:使用 clientHeight 和 clientWidth我们都清楚...

前端达人 1万+
上一篇: 小白也能秒懂:Canvas全局透明度globalAlpha实战指南(附避坑技
下一篇: Canvas文字自动换行太难搞?手把手教你封装自定义扩展方法
master_chenchengg
博客等级 码龄2年 1万+粉丝 1485原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值