在开发中遇到了需要获取一段文字的长度的技术性需求,这篇文章将会讲述我是如何解决这样的问题的
浏览器环境下
解决方法一: SPAN标签
我最开始的解决方法是创建一个span
元素,然后innerHTML
设置文本在设置好样式后插入到body
中,读取宽高
1 | function getCharSize(char, style = {}){ |

问题
不同浏览器的差异
不同浏览器获取的高度宽高有一些差别
chrome:
firefox:
不知道为何
firefox
的高总是比chrome
高2px,但这个我们可以通过直接获取传入的fontSize
作为高,这样就可以统一了1
2
3
4
5
6
7
8
9
10
11function getCharSize(char, style = {}){
let {
fontSize = 14,
fontFamily = "SimSun"
} = style
/*其他操作*/
return {
width,
height: fontSize
}
}浏览器对字体大小的限制
chrome默认最小字体为12px,基本是人尽皆知的
这里可以使用scale的方式实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17function getCharSize(char, style = {}){
let {
fontSize = 14,
fontFamily = "SimSun"
} = style
/*其他操作*/
let scale = fontSize / 20
span.style.fontSize = `${20}px`
span.style.transform = `scale(${scale})`
span.style.display = "inline-block" //让scale生效
/*其他操作*/
return {
width,
height: fontSize
}
}
优点
兼容几乎所有浏览器
缺点
会受一些潜在的全局样式影响
解决方法二:Canvas measureText函数
除了使用span来获取浏览器表现的大小这样直接的方式以外,还有可以通过使用canvasAPI的CanvasRenderingContext2D.measureText()方式来快速获取
1 | const ctx = document.createElement('canvas').getContext('2d') |
问题
chrome浏览器存在BUG,如果canvas不在DOM树上设置字体大小小于12px时,字体大小会强制设置为12px
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//setfont before append
const canvas1 = document.createElement('canvas')
canvas1.width = 100
canvas1.height = 100
const ctx1 = canvas1.getContext('2d')
ctx1.font = "8px Arial"
ctx1.fillText(ctx1.font, 0, 50)
document.body.appendChild(canvas1)
//set font after append
const canvas2 = document.createElement('canvas')
canvas2.width = 100
canvas2.height = 100
const ctx2 = canvas2.getContext('2d')
document.body.appendChild(canvas2)
ctx2.font = "8px Arial"
ctx2.fillText(ctx2.font, 0, 50)
代码整理
下面给出优化后的代码
方法一:span
1 | let span = document.createElement("span") |
方法二:canvas计算
1 | let canvas = document.createElement('canvas') |
性能比较
数据为进行10000次单字符计算
都需要插入DOM的情况下(方法二兼容chrome,且字体都为12px以下)
方法二效率比方法一快: 150%左右
方法二字体都为12px以上
方法二效率比方法一快: 1500%左右
从效率上来讲,canvas效率是极高的,同时canvas还有还在制定的标准,可以提供更加详细的文本信息,chrome只需要去chrome://flags/
开启Experimental Extension APIs
(新版本)或Experimental Extension APIs
(老版本)就可以提前使用该功能

参考资料
CanvasRenderingContext2D.measureText()
END
2019-01-15 更新:谷歌浏览器开启flag的实验特性有改变(Experimental Extension APIs)
2018-03-31 完成
2017-12-13 立项