为什么 HTML5 使用 offsetWidth 测量的文本在两个不同的时间点对阿拉伯文本给出两个不同的结果

Why is HTML5 text measuring with offsetWidth giving two different results for Arabic text at two different points in time

我刚刚记录了这些用于测量阿拉伯文本的值 el.offsetWidth:

t1 t2
-----
35 87 "بِسْمِ بِسْمِ"
77 114 "بِسْمِ ٱللَّهِ ٱللَّهِ"
150 224 "بِسْمِ ٱللَّهِ ٱلرَّحْمَنِ ٱلرَّحْمَنِ"
215 279 "بِسْمِ ٱللَّهِ ٱلرَّحْمَنِ ٱلرَّحِيمِ ٱلرَّحِيمِ"
221 227 "بِسْمِ ٱللَّهِ ٱلرَّحْمَنِ ٱلرَّحِيمِ ‎ ‎"
281 341 "بِسْمِ ٱللَّهِ ٱلرَّحْمَنِ ٱلرَّحِيمِ ‎ ٱلْحَمْدُ ٱلْحَمْدُ"
312 344 "بِسْمِ ٱللَّهِ ٱلرَّحْمَنِ ٱلرَّحِيمِ ‎ ٱلْحَمْدُ لِلَّهِ لِلَّهِ"
351 390 "بِسْمِ ٱللَّهِ ٱلرَّحْمَنِ ٱلرَّحِيمِ ‎ ٱلْحَمْدُ لِلَّهِ رَبِّ رَبِّ"
429 508 "بِسْمِ ٱللَّهِ ٱلرَّحْمَنِ ٱلرَّحِيمِ ‎ ٱلْحَمْدُ لِلَّهِ رَبِّ ٱلْعَلَمِينَ ٱلْعَلَمِينَ"
436 442 "بِسْمِ ٱللَّهِ ٱلرَّحْمَنِ ٱلرَّحِيمِ ‎ ٱلْحَمْدُ لِلَّهِ رَبِّ ٱلْعَلَمِينَ ‎ ‎"
509 582 "بِسْمِ ٱللَّهِ ٱلرَّحْمَنِ ٱلرَّحِيمِ ‎ ٱلْحَمْدُ لِلَّهِ رَبِّ ٱلْعَلَمِينَ ‎ ٱلرَّحْمَنِ ٱلرَّحْمَنِ"
573 122 "ٱلرَّحِيمِ ٱلرَّحِيمِ"
64 70 "ٱلرَّحِيمِ ‎ ‎"
112 161 "ٱلرَّحِيمِ ‎ مَلِكِ مَلِكِ"
149 185 "ٱلرَّحِيمِ ‎ مَلِكِ يَوْمِ يَوْمِ"
204 260 "ٱلرَّحِيمِ ‎ مَلِكِ يَوْمِ ٱلدِّينِ ٱلدِّينِ"
211 217 "ٱلرَّحِيمِ ‎ مَلِكِ يَوْمِ ٱلدِّينِ ‎ ‎"
258 305 "ٱلرَّحِيمِ ‎ مَلِكِ يَوْمِ ٱلدِّينِ ‎ إِيَّاكَ إِيَّاكَ"
304 350 "ٱلرَّحِيمِ ‎ مَلِكِ يَوْمِ ٱلدِّينِ ‎ إِيَّاكَ نَعْبُدُ نَعْبُدُ"
362 420 "ٱلرَّحِيمِ ‎ مَلِكِ يَوْمِ ٱلدِّينِ ‎ إِيَّاكَ نَعْبُدُ وَإِيَّاكَ وَإِيَّاكَ"
443 524 "ٱلرَّحِيمِ ‎ مَلِكِ يَوْمِ ٱلدِّينِ ‎ إِيَّاكَ نَعْبُدُ وَإِيَّاكَ نَسْتَعِينُ نَسْتَعِينُ"
449 456 "ٱلرَّحِيمِ ‎ مَلِكِ يَوْمِ ٱلدِّينِ ‎ إِيَّاكَ نَعْبُدُ وَإِيَّاكَ نَسْتَعِينُ ‎ ‎"
501 553 "ٱلرَّحِيمِ ‎ مَلِكِ يَوْمِ ٱلدِّينِ ‎ إِيَّاكَ نَعْبُدُ وَإِيَّاكَ نَسْتَعِينُ ‎ ٱهْدِنَا ٱهْدِنَا"
571 132 "ٱلصِّرَطَ ٱلصِّرَطَ"
159 254 "ٱلصِّرَطَ ٱلْمُسْتَقِيمَ ٱلْمُسْتَقِيمَ"
165 171 "ٱلصِّرَطَ ٱلْمُسْتَقِيمَ ‎ ‎"
221 278 "ٱلصِّرَطَ ٱلْمُسْتَقِيمَ ‎ صِرَطَ صِرَطَ"
277 332 "ٱلصِّرَطَ ٱلْمُسْتَقِيمَ ‎ صِرَطَ ٱلَّذِينَ ٱلَّذِينَ"
348 419 "ٱلصِّرَطَ ٱلْمُسْتَقِيمَ ‎ صِرَطَ ٱلَّذِينَ أَنْعَمْتَ أَنْعَمْتَ"
408 468 "ٱلصِّرَطَ ٱلْمُسْتَقِيمَ ‎ صِرَطَ ٱلَّذِينَ أَنْعَمْتَ عَلَيْهِمْ عَلَيْهِمْ"
445 481 "ٱلصِّرَطَ ٱلْمُسْتَقِيمَ ‎ صِرَطَ ٱلَّذِينَ أَنْعَمْتَ عَلَيْهِمْ غَيْرِ غَيْرِ"
547 650 "ٱلصِّرَطَ ٱلْمُسْتَقِيمَ ‎ صِرَطَ ٱلَّذِينَ أَنْعَمْتَ عَلَيْهِمْ غَيْرِ ٱلْمَغْضُوبِ ٱلْمَغْضُوبِ"
607 114 "عَلَيْهِمْ عَلَيْهِمْ"
85 116 "عَلَيْهِمْ وَلَا وَلَا"
165 246 "عَلَيْهِمْ وَلَا ٱلضَّآلِّينَ ٱلضَّآلِّينَ"
172 178 "عَلَيْهِمْ وَلَا ٱلضَّآلِّينَ ‎ ‎"
203 235 "عَلَيْهِمْ وَلَا ٱلضَّآلِّينَ ‎ الٓمٓ الٓمٓ"
210 216 "عَلَيْهِمْ وَلَا ٱلضَّآلِّينَ ‎ الٓمٓ ‎ ‎"
256 302 "عَلَيْهِمْ وَلَا ٱلضَّآلِّينَ ‎ الٓمٓ ‎ 

代码本质上是这样的:

var measurer = document.createElement('span')
document.body.appendChild(measurer)

var strings = [
  'arabic string 1...',
  'arabic string 2...',
  ...
]

next()

function next() {
  var string = strings.shift()
  var s1 = measure(string)
  setTimeout(function(){
    var s2 = measure(string)
    console.log(s1, s2, string)
    next()
  }, 300)
}

function measure(string) {
  measurer.innerHTML = string
  return measurer.offsetWidth
}

为什么要这样做?为什么最终值 "after I've waited for a little while" 通常大于最初计算的 offsetWidth 值?我如何准确计算这些?

我无法重现您的发现(使用您的代码的简化版本和您提供的字符串示例)。

const measurer = document.createElement('span');
document.body.appendChild(measurer);

const strings = [
  "بِسْمِ ٱللَّهِ ٱلرَّحْمَنِ ٱلرَّحْمَنِ",
  "بِسْمِ ٱللَّهِ ٱلرَّحْمَنِ ٱلرَّحِيمِ ‎ ٱلْحَمْدُ لِلَّهِ رَبِّ ٱلْعَلَمِينَ ‎ ٱلرَّحْمَنِ ٱلرَّحْمَنِ",
  "ٱلرَّحِيمِ ‎ مَلِكِ يَوْمِ ٱلدِّينِ ‎ إِيَّاكَ نَعْبُدُ نَعْبُدُ",
  "ٱلصِّرَطَ ٱلْمُسْتَقِيمَ ‎ صِرَطَ ٱلَّذِينَ ٱلَّذِينَ"
];

console.log("t1 t2 string\n--------------------------");
strings.forEach(next);

function next(str) {
  const s1 = measure(str);
  setTimeout( () => console.log(s1, measure(str), str), 300);
}

function measure(string) {
  measurer.innerHTML = string;
  return measurer.offsetWidth;
}