【问题标题】:Calculate text width with JavaScript用 JavaScript 计算文本宽度
【发布时间】:2010-09-12 04:57:17
【问题描述】:

我想使用 JavaScript 来计算字符串的宽度。这是否可能无需使用等宽字体?

如果不是内置的,我唯一的想法是为每个字符创建一个宽度表,但这非常不合理,尤其是支持 Unicode 和不同的字体大小(以及所有浏览器)。

【问题讨论】:

  • 请注意,如果您使用外部字体,则必须在加载后使用以下技术。如果您将它们缓存或安装了本地版本,您可能不会意识到这一点。

标签: javascript textbox


【解决方案1】:

创建一个具有以下样式的 DIV。在您的 JavaScript 中,设置您尝试测量的字体大小和属性,将您的字符串放入 DIV,然后读取 DIV 的当前宽度和高度。它将拉伸以适应内容,并且大小将在字符串呈现大小的几个像素内。

var fontSize = 12;
var test = document.getElementById("Test");
test.style.fontSize = fontSize;
var height = (test.clientHeight + 1) + "px";
var width = (test.clientWidth + 1) + "px"

console.log(height, width);
#Test
{
    position: absolute;
    visibility: hidden;
    height: auto;
    width: auto;
    white-space: nowrap; /* Thanks to Herb Caudill comment */
}
<div id="Test">
    abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
</div>

【讨论】:

  • 我唯一要补充的是,根据使用的样式,这可能会给出错误的尺寸。请记住,您可能有像 p { letter-spacing: 0.1em; 这样的样式。 } DIV 元素不会反映。您必须确保适当的样式适合您将使用文本的位置。
  • 同上 Jim 的评论 - 仔细检查以确保容器(在本例中为 div)没有通过您当时可能不知道的 css 选择规则应用任何其他样式。在测量之前应用您关心的样式之前,从容器中删除所有相关样式。
  • 如果您认为文本会超出浏览器宽度,您还应该输入 white-space:nowrap。
  • @BBog 所有这些乱七八糟的东西就是为什么我建议在楼下采取一种不同的、不那么老套的方法。看看吧here.
  • 只是好奇+1 在每个维度上的作用是什么?
【解决方案2】:
<span id="text">Text</span>

<script>
var textWidth = document.getElementById("text").offsetWidth;
</script>

只要 标签没有应用其他样式,这应该可以工作。 offsetWidth 将包括任何边框的宽度、水平填充、垂直滚动条宽度等。

【讨论】:

  • 这或多或少是构成上层解决方案的原因,但是由于您的文本可能被分成几行,它们会在文本中添加一些 CSS 样式以获得真正的全文宽度。
【解决方案3】:

ExtJS javascript library 有一个很棒的类,叫做 Ext.util.TextMetrics,它“为文本块提供精确的像素测量,以便您可以准确地确定给定文本块的高度和宽度(以像素为单位)”。您可以直接使用它,也可以查看其源代码以了解它是如何完成的。

http://docs.sencha.com/extjs/6.5.3/modern/Ext.util.TextMetrics.html

【讨论】:

  • ExtJS 有一个奇怪的许可证。要么您向当前的维护者、Sencha 公司付费以使用它,要么您必须开源您的应用程序中的所有相关代码。对于大多数公司来说,这是一个表演障碍。另一方面,jQuery 使用高度宽松的 MIT 许可证。
  • javascript不是自动满足开源的要求吗?您将源提供给查看该页面的任何人。
  • 能够查看源代码和开源是有区别的,这是由许可定义的。
  • 感谢我们这些仍在使用 ExtJS 的人 :-)
  • 你应该让 ExtJS 安息
【解决方案4】:

jQuery:

(function($) {

 $.textMetrics = function(el) {

  var h = 0, w = 0;

  var div = document.createElement('div');
  document.body.appendChild(div);
  $(div).css({
   position: 'absolute',
   left: -1000,
   top: -1000,
   display: 'none'
  });

  $(div).html($(el).html());
  var styles = ['font-size','font-style', 'font-weight', 'font-family','line-height', 'text-transform', 'letter-spacing'];
  $(styles).each(function() {
   var s = this.toString();
   $(div).css(s, $(el).css(s));
  });

  h = $(div).outerHeight();
  w = $(div).outerWidth();

  $(div).remove();

  var ret = {
   height: h,
   width: w
  };

  return ret;
 }

})(jQuery);

【讨论】:

    【解决方案5】:

    下面的代码片段,“计算”跨度标签的宽度,如果它太长,则附加“...”并减少文本长度,直到它适合其父级(或直到它有试了一千多次)

    CSS

    div.places {
      width : 100px;
    }
    div.places span {
      white-space:nowrap;
      overflow:hidden;
    }
    

    HTML

    <div class="places">
      <span>This is my house</span>
    </div>
    <div class="places">
      <span>And my house are your house</span>
    </div>
    <div class="places">
      <span>This placename is most certainly too wide to fit</span>
    </div>
    

    JavaScript(带有 jQ​​uery)

    // loops elements classed "places" and checks if their child "span" is too long to fit
    $(".places").each(function (index, item) {
        var obj = $(item).find("span");
        if (obj.length) {
            var placename = $(obj).text();
            if ($(obj).width() > $(item).width() && placename.trim().length > 0) {
                var limit = 0;
                do {
                    limit++;
                                        placename = placename.substring(0, placename.length - 1);
                                        $(obj).text(placename + "...");
                } while ($(obj).width() > $(item).width() && limit < 1000)
            }
        }
    });
    

    【讨论】:

    • 尝试二进制搜索而不是一次循环 1 个字符:请参阅我对 Alex 对 stackoverflow.com/questions/536814/… 的回答的评论
    • @StanleyH:好主意 - 我会尽快实施您的建议。
    【解决方案6】:

    这对我有用...

    // Handy JavaScript to measure the size taken to render the supplied text;
    // you can supply additional style information too if you have it.
    
    function measureText(pText, pFontSize, pStyle) {
        var lDiv = document.createElement('div');
    
        document.body.appendChild(lDiv);
    
        if (pStyle != null) {
            lDiv.style = pStyle;
        }
        lDiv.style.fontSize = "" + pFontSize + "px";
        lDiv.style.position = "absolute";
        lDiv.style.left = -1000;
        lDiv.style.top = -1000;
    
        lDiv.innerHTML = pText;
    
        var lResult = {
            width: lDiv.clientWidth,
            height: lDiv.clientHeight
        };
    
        document.body.removeChild(lDiv);
        lDiv = null;
    
        return lResult;
    }
    

    【讨论】:

    • 您好,您的回答真的很有帮助,但是使用 .cssText 而不是 .style 来支持 IE 8 及更低版本..
    • 这个答案很好,但是当我生成一大段文本时,它会变得不准确。是不是因为宽度不是整数?
    • 请勿在当前状态下使用此解决方案。使用 textContent 代替 innerHTML 来解决 XSS 漏洞。
    【解决方案7】:

    这是我在没有示例的情况下拼凑在一起的。看起来我们都在同一个页面上。

    String.prototype.width = function(font) {
      var f = font || '12px arial',
          o = $('<div></div>')
                .text(this)
                .css({'position': 'absolute', 'float': 'left', 'white-space': 'nowrap', 'visibility': 'hidden', 'font': f})
                .appendTo($('body')),
          w = o.width();
    
      o.remove();
    
      return w;
    }
    

    使用很简单:"a string".width()

    **添加了white-space: nowrap,这样可以计算宽度大于窗口宽度的字符串。

    【讨论】:

    • 感谢 JordanC。我要补充的一件事是,如果您在同一页面上多次调用它,并且性能是一个问题,您可以保留 DIV,只需更改内容并检查宽度。我就是这样做的,所以一旦一切都说完了,DOM 就会和你开始时一样
    • 在我的版本中,我使用了一个对象而不是字体参数,因此您可以为 div 提供粗体和斜体等 css 参数。
    • 我不会将此方法添加到String,因为它会减少您程序的separation of concerns(单独的核心代码与UI 代码)。想象一下,您想将核心代码移植到具有完全不同 UI 框架的平台......
    • 这是糟糕的设计,它不仅将您的模型与您的视图耦合,而且还直接与 jQuery 耦合。最重要的是,这是回流地狱,这肯定不会很好地扩展。
    • 如果你想要浮点值,你可以使用o[0].getBoundingClientRect().width,这里建议:stackoverflow.com/a/16072668/936397
    【解决方案8】:

    您可以使用画布,这样您就不必过多地处理 css 属性:

    var canvas = document.createElement("canvas");
    var ctx = canvas.getContext("2d");
    ctx.font = "20pt Arial";  // This can be set programmaticly from the element's font-style if desired
    var textWidth = ctx.measureText($("#myElement").text()).width;
    

    【讨论】:

    • 这不是比创建 DOM 元素并为其指定 css 属性更重量级(获取 2d 上下文等)吗?
    • 如果您已经在使用画布做某事,这是一种干净的方法。但是很慢。单独调用 measureText 大约需要 8-10 毫秒(使用 Chrome)。
    【解决方案9】:

    试试这个代码:

    function GetTextRectToPixels(obj)
    {
    var tmpRect = obj.getBoundingClientRect();
    obj.style.width = "auto"; 
    obj.style.height = "auto"; 
    var Ret = obj.getBoundingClientRect(); 
    obj.style.width = (tmpRect.right - tmpRect.left).toString() + "px";
    obj.style.height = (tmpRect.bottom - tmpRect.top).toString() + "px"; 
    return Ret;
    }
    

    【讨论】:

      【解决方案10】:

      文字的宽度和高度可以通过clientWidth和clientHeight获得

      var element = document.getElementById ("mytext");
      
      var width = element.clientWidth;
      var height = element.clientHeight;
      

      确保样式位置属性设置为绝对

      element.style.position = "absolute";
      

      不需要在div 内,可以在p 或span 内

      【讨论】:

        【解决方案11】:

        更好的是在显示元素之前检测文本是否适合。所以你可以使用这个不需要元素在屏幕上的功能。

        function textWidth(text, fontProp) {
            var tag = document.createElement("div");
            tag.style.position = "absolute";
            tag.style.left = "-999em";
            tag.style.whiteSpace = "nowrap";
            tag.style.font = fontProp;
            tag.innerHTML = text;
        
            document.body.appendChild(tag);
        
            var result = tag.clientWidth;
        
            document.body.removeChild(tag);
        
            return result;
        }
        

        用法:

        if ( textWidth("Text", "bold 13px Verdana") > elementWidth) {
            ...
        }
        

        【讨论】:

          【解决方案12】:
          var textWidth = (function (el) {
              el.style.position = 'absolute';
              el.style.top = '-1000px';
              document.body.appendChild(el);
          
              return function (text) {
                  el.innerHTML = text;
                  return el.clientWidth;
              };
          })(document.createElement('div'));
          

          【讨论】:

            【解决方案13】:

            在HTML 5中,您可以只使用Canvas.measureText method(进一步解释here)。

            Try this fiddle:

            /**
              * Uses canvas.measureText to compute and return the width of the given text of given font in pixels.
              * 
              * @param {String} text The text to be rendered.
              * @param {String} font The css font descriptor that text is to be rendered with (e.g. "bold 14px verdana").
              * 
              * @see https://stackoverflow.com/questions/118241/calculate-text-width-with-javascript/21015393#21015393
              */
            function getTextWidth(text, font) {
              // re-use canvas object for better performance
              const canvas = getTextWidth.canvas || (getTextWidth.canvas = document.createElement("canvas"));
              const context = canvas.getContext("2d");
              context.font = font;
              const metrics = context.measureText(text);
              return metrics.width;
            }
            
            function getCssStyle(element, prop) {
                return window.getComputedStyle(element, null).getPropertyValue(prop);
            }
            
            function getCanvasFontSize(el = document.body) {
              const fontWeight = getCssStyle(el, 'font-weight') || 'normal';
              const fontSize = getCssStyle(el, 'font-size') || '16px';
              const fontFamily = getCssStyle(el, 'font-family') || 'Times New Roman';
              
              return `${fontWeight} ${fontSize} ${fontFamily}`;
            }
            
            console.log(getTextWidth("hello there!", "bold 12pt arial"));  // close to 86
            

            如果您想使用某些特定元素myEl 的字体大小,可以使用getCanvasFontSize 实用函数:

            const fontSize = getTextWidth(text, getCanvasFontSize(myEl));
            // do something with fontSize here...
            

            解释:getCanvasFontSize 函数采用某些元素(默认情况下:body's)字体并将其转换为与Context.font property 兼容的格式。当然,任何元素在使用前都必须先添加到 DOM,否则它会给你虚假值。

            el.remove()); // hackfix:不要这样做! 返回 el; } 控制台.log(getTextWidth( “你好呀!”, getCanvasFontSize(createEl('span')) )); 控制台.log(getTextWidth( “你好呀!”, getCanvasFontSize(createEl('h1')) )); ``` -->

            更多注意事项

            这种方法有几个优点,包括:

            • 比其他(基于 DOM)的方法更简洁、更安全,因为它不会更改全局状态,例如您的 DOM。
            • modifying more canvas text properties 可以进一步自定义,例如textAlign 和textBaseline。

            注意:将文本添加到 DOM 时,请记住还要考虑 padding, margin and border。

            注意 2:在某些浏览器上,此方法会产生亚像素精度(结果是浮点数),而在其他浏览器上则不会(结果只是 int)。您可能希望在结果上运行Math.floor(或Math.ceil)以避免不一致。由于基于 DOM 的方法从来都不是亚像素精度的,因此这种方法的精度比这里的其他方法还要高。

            根据this jsperf(感谢 cmets 的贡献者),如果添加缓存,Canvas 方法 和 基于 DOM 的方法 速度差不多基于 DOM 的方法,而您没有使用 Firefox。在 Firefox 中,出于某种原因,这种 Canvas 方法 比 基于 DOM 的方法 快得多(截至 2014 年 9 月)。

            性能

            This fiddle 将此 Canvas 方法与Bob Monteverde's DOM-based method 的变体进行比较,因此您可以分析和比较结果的准确性。

            【讨论】:

            • 这是一个很棒的选择,我不知道。是否曾经将其性能与在 DOM 中测量的性能进行比较?
            • 我将缓存添加到该 jsperf 基准测试中。现在这两种方法差不多:jsperf.com/measure-text-width/4
            • @Martin 嗯? “许多 HTML 元素”与这里的任何东西有什么关系?此示例中的画布对象甚至没有附加到 DOM。甚至除此之外,在您 strokeText() 或 fillText() 之前,更改画布绘图上下文中的字体甚至根本不会影响画布。也许您打算对不同的答案发表评论?
            • 不错的解决方案。我已经围绕 Domi 的答案包装了其他几种方法,以便我可以 - 如果它不适合给定的空间(尽可能多的字符串尽可能使用) - 传入一个包含(可能被截断的)字符串的 JQuery 元素,并动态确定字体属性,以便不必对它们进行硬编码,从而允许 CSS 字体属性更改而不会中断布局。 JSFiddle 这里:jsfiddle.net/brebey/1q94gLsu/6/embed
            • 很好,因为用户看不到它!
            【解决方案14】:

            为此我写了一个小工具。也许它对某人有用。 没有 jQuery 也可以工作。

            https://github.com/schickling/calculate-size

            用法:

            var size = calculateSize("Hello world!", {
               font: 'Arial',
               fontSize: '12px'
            });
            
            console.log(size.width); // 65
            console.log(size.height); // 14
            

            小提琴:http://jsfiddle.net/PEvL8/

            【讨论】:

              【解决方案15】:

              我想这与 Depak 条目非常相似,但基于 Louis Lazaris 的作品,该作品发表在 impressivewebs page 的一篇文章中

              (function($){
              
                      $.fn.autofit = function() {             
              
                          var hiddenDiv = $(document.createElement('div')),
                          content = null;
              
                          hiddenDiv.css('display','none');
              
                          $('body').append(hiddenDiv);
              
                          $(this).bind('fit keyup keydown blur update focus',function () {
                              content = $(this).val();
              
                              content = content.replace(/\n/g, '<br>');
                              hiddenDiv.html(content);
              
                              $(this).css('width', hiddenDiv.width());
              
                          });
              
                          return this;
              
                      };
                  })(jQuery);
              

              fit事件用于在函数关联到控件后立即执行函数调用。

              例如:$('input').autofit().trigger("fit");

              【讨论】:

                【解决方案16】:

                没有 jQuery:

                String.prototype.width = function (fontSize) {
                    var el,
                        f = fontSize + " px arial" || '12px arial';
                    el = document.createElement('div');
                    el.style.position = 'absolute';
                    el.style.float = "left";
                    el.style.whiteSpace = 'nowrap';
                    el.style.visibility = 'hidden';
                    el.style.font = f;
                    el.innerHTML = this;
                    el = document.body.appendChild(el);
                    w = el.offsetWidth;
                    el.parentNode.removeChild(el);
                    return w;
                }
                
                // Usage
                "MyString".width(12);
                

                【讨论】:

                • 设置数字时不起作用,因为不需要空格,如果删除它,它会正常工作:fontSize + "px arial" -> fontSize + "px arial",就是这样.
                【解决方案17】:

                工作示例的小提琴:http://jsfiddle.net/tdpLdqpo/1/

                HTML:

                <h1 id="test1">
                    How wide is this text?
                </h1>
                <div id="result1"></div>
                <hr/>
                <p id="test2">
                    How wide is this text?
                </p>
                <div id="result2"></div>
                <hr/>
                <p id="test3">
                    How wide is this text?<br/><br/>
                    f sdfj f sdlfj lfj lsdk jflsjd fljsd flj sflj sldfj lsdfjlsdjkf sfjoifoewj flsdjfl jofjlgjdlsfjsdofjisdojfsdmfnnfoisjfoi  ojfo dsjfo jdsofjsodnfo sjfoj ifjjfoewj fofew jfos fojo foew jofj s f j
                </p>
                <div id="result3"></div>
                

                JavaScript 代码:

                function getTextWidth(text, font) {
                    var canvas = getTextWidth.canvas ||
                        (getTextWidth.canvas = document.createElement("canvas"));
                    var context = canvas.getContext("2d");
                    context.font = font;
                    var metrics = context.measureText(text);
                    return metrics.width;
                };
                
                $("#result1")
                .text("answer: " +
                    getTextWidth(
                             $("#test1").text(),
                             $("#test1").css("font")) + " px");
                
                $("#result2")
                    .text("answer: " +
                        getTextWidth(
                             $("#test2").text(),
                             $("#test2").css("font")) + " px");
                
                $("#result3")
                    .text("answer: " +
                        getTextWidth(
                             $("#test3").text(),
                             $("#test3").css("font")) + " px");
                

                【讨论】:

                • 这段代码只显示纯文本的宽度,它忽略了fontFamily、fontSize、fontWeight等
                【解决方案18】:

                在Deepak Nadar's answer 的基础上,我更改了函数参数以接受文本和字体样式。您不需要引用元素。此外,fontOptions 具有默认值,因此您无需提供所有这些值。

                (function($) {
                  $.format = function(format) {
                    return (function(format, args) {
                      return format.replace(/{(\d+)}/g, function(val, pos) {
                        return typeof args[pos] !== 'undefined' ? args[pos] : val;
                      });
                    }(format, [].slice.call(arguments, 1)));
                  };
                  $.measureText = function(html, fontOptions) {
                    fontOptions = $.extend({
                      fontSize: '1em',
                      fontStyle: 'normal',
                      fontWeight: 'normal',
                      fontFamily: 'arial'
                    }, fontOptions);
                    var $el = $('<div>', {
                      html: html,
                      css: {
                        position: 'absolute',
                        left: -1000,
                        top: -1000,
                        display: 'none'
                      }
                    }).appendTo('body');
                    $(fontOptions).each(function(index, option) {
                      $el.css(option, fontOptions[option]);
                    });
                    var h = $el.outerHeight(), w = $el.outerWidth();
                    $el.remove();
                    return { height: h, width: w };
                  };
                }(jQuery));
                
                var dimensions = $.measureText("Hello World!", { fontWeight: 'bold', fontFamily: 'arial' });
                
                // Font Dimensions: 94px x 18px
                $('body').append('<p>').text($.format('Font Dimensions: {0}px x {1}px', dimensions.width, dimensions.height));
                &lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"&gt;&lt;/script&gt;

                【讨论】:

                  【解决方案19】:

                  我喜欢你做一个静态字符宽度映射的“唯一想法”!它实际上很适合我的目的。有时,出于性能原因或因为您无法轻松访问 DOM,您可能只需要一个快速的 hacky 独立计算器,校准为单一字体。所以这里有一个校准到 Helvetica 的;传递一个字符串和一个字体大小:

                  const widths = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.2796875,0.2765625,0.3546875,0.5546875,0.5546875,0.8890625,0.665625,0.190625,0.3328125,0.3328125,0.3890625,0.5828125,0.2765625,0.3328125,0.2765625,0.3015625,0.5546875,0.5546875,0.5546875,0.5546875,0.5546875,0.5546875,0.5546875,0.5546875,0.5546875,0.5546875,0.2765625,0.2765625,0.584375,0.5828125,0.584375,0.5546875,1.0140625,0.665625,0.665625,0.721875,0.721875,0.665625,0.609375,0.7765625,0.721875,0.2765625,0.5,0.665625,0.5546875,0.8328125,0.721875,0.7765625,0.665625,0.7765625,0.721875,0.665625,0.609375,0.721875,0.665625,0.94375,0.665625,0.665625,0.609375,0.2765625,0.3546875,0.2765625,0.4765625,0.5546875,0.3328125,0.5546875,0.5546875,0.5,0.5546875,0.5546875,0.2765625,0.5546875,0.5546875,0.221875,0.240625,0.5,0.221875,0.8328125,0.5546875,0.5546875,0.5546875,0.5546875,0.3328125,0.5,0.2765625,0.5546875,0.5,0.721875,0.5,0.5,0.5,0.3546875,0.259375,0.353125,0.5890625]
                  const avg = 0.5279276315789471
                  
                  function measureText(str, fontSize) {
                    return Array.from(str).reduce(
                      (acc, cur) => acc + (widths[cur.charCodeAt(0)] ?? avg), 0
                    ) * fontSize
                  }
                  

                  那个巨大的丑陋数组是由字符代码索引的 ASCII 字符宽度。所以这只支持ASCII(否则它假设一个平均字符宽度)。幸运的是,宽度基本上与字体大小成线性关系,因此它在任何字体大小下都能很好地工作。它明显缺乏对字距调整或连字等的任何认识。

                  为了“校准”,我只是在 svg 上将每个字符渲染到 charCode 126(强大的波浪号),然后得到边界框并将其保存到这个数组中; more code and explanation and demo here.

                  【讨论】:

                  • 这是一个聪明的解决方案,很好:) 我总是使用相同的字体/大小,所以它很适合我。我发现 DOM/Canvas 解决方案的性能确实存在问题,这真的很干净,干杯!
                  • 不再需要画布+1
                  • 你可以去掉* fontSize,直接使用'em'
                  • 多么棒的答案!
                  • 当心,这并没有考虑到每个现代字体用于光学校正特定字形之间的间距/跟踪的字距调整对。
                  【解决方案20】:

                  Element.getClientRects() 方法返回 DOMRect 对象的集合,这些对象指示客户端中每个 CSS 边框框的边界矩形。返回值是DOMRect 对象的集合,每个对象对应一个与该元素关联的 CSS 边框框。每个DOMRect 对象都包含只读的left、top、right 和bottom 属性,用于描述边界框,以像素为单位,左上角相对于视口的左上角。

                  Element.getClientRects() by Mozilla Contributors 在CC-BY-SA 2.5 下获得许可。

                  将所有返回的矩形宽度相加得出总文本宽度(以像素为单位)。

                  document.getElementById('in').addEventListener('input', function (event) {
                      var span = document.getElementById('text-render')
                      span.innerText = event.target.value
                      var rects = span.getClientRects()
                      var widthSum = 0
                      for (var i = 0; i < rects.length; i++) {
                          widthSum += rects[i].right - rects[i].left
                      }
                      document.getElementById('width-sum').value = widthSum
                  })
                  <p><textarea id='in'></textarea></p>
                  <p><span id='text-render'></span></p>
                  <p>Sum of all widths: <output id='width-sum'>0</output>px</p>

                  【讨论】:

                    【解决方案21】:

                    万一其他人来到这里寻找一种方法来测量字符串的宽度和一种方法来了解适合特定宽度的最大字体大小,这里有一个函数以@Domi's solution 为基础,采用二分搜索:

                    /**
                     * Find the largest font size (in pixels) that allows the string to fit in the given width.
                     * 
                     * @param {String} text - The text to be rendered.
                     * @param {String} font - The css font descriptor that text is to be rendered with (e.g. "bold ?px verdana") -- note the use of ? in place of the font size.
                     * @param {Number} width - The width in pixels the string must fit in
                     * @param {Number} minFontPx - The smallest acceptable font size in pixels
                     * @param {Number} maxFontPx - The largest acceptable font size in pixels
                     **/
                    function GetTextSizeForWidth(text, font, width, minFontPx, maxFontPx) {
                      for (;;) {
                        var s = font.replace("?", maxFontPx);
                        var w = GetTextWidth(text, s);
                        if (w <= width) {
                          return maxFontPx;
                        }
                    
                        var g = (minFontPx + maxFontPx) / 2;
                    
                        if (Math.round(g) == Math.round(minFontPx) || Math.round(g) == Math.round(maxFontPx)) {
                          return g;
                        }
                    
                        s = font.replace("?", g);
                        w = GetTextWidth(text, s);
                        if (w >= width) {
                          maxFontPx = g;
                        } else {
                          minFontPx = g;
                        }
                      }
                    }
                    

                    【讨论】:

                    • 这非常有效(加上 Domi 的回答中的代码)
                    【解决方案22】:

                    从头开始重写我的答案(感谢那个减号)。 现在函数接受要应用的文本和 css 规则(并且不再使用 jQuery)。所以它也会尊重填充。结果值被四舍五入(你可以在那里看到 Math.round,如果你想要更精确的值,请删除)

                    function getSpan(){
                        const span = document.createElement('span')
                        span.style.position = 'fixed';
                        span.style.visibility = 'hidden';
                        document.body.appendChild(span);
                        return span;
                    }
                    
                    function textWidth(str, css) {
                        const span = getSpan();
                        Object.assign(span.style, css || {});
                        span.innerText = str;
                        const w = Math.round(span.getBoundingClientRect().width);
                        
                        span.remove();
                        
                        return w;
                    }
                    
                    
                    const testStyles = [
                      {fontSize: '10px'},
                      {fontSize: '12px'},
                      {fontSize: '60px'},
                      {fontSize: '120px'},
                      {fontSize: '120px', padding: '10px'},
                      {fontSize: '120px', fontFamily: 'arial'},
                      {fontSize: '120px', fontFamily: 'tahoma'},
                      {fontSize: '120px', fontFamily: 'tahoma', padding: '5px'},
                    ];
                    
                    const ul = document.getElementById('output');
                    testStyles.forEach(style => {
                      const li = document.createElement('li');
                      li.innerText = `${JSON.stringify(style)} > ${textWidth('abc', style)}`;
                      ul.appendChild(li);
                    });
                    &lt;ul id="output"&gt;&lt;/ul&gt;

                    【讨论】:

                      【解决方案23】:

                      您也可以使用 createRange 来做到这一点,它比文本克隆技术更准确:

                      function getNodeTextWidth(nodeWithText) {
                          var textNode = $(nodeWithText).contents().filter(function () {
                              return this.nodeType == Node.TEXT_NODE;
                          })[0];
                          var range = document.createRange();
                          range.selectNode(textNode);
                          return range.getBoundingClientRect().width;
                      }
                      

                      【讨论】:

                        【解决方案24】:

                        我正在使用text-metrics 包。效果很好,我试过这个solution,但由于某些原因,它算错了。

                        textMetrics.init(document.querySelector('h1'), { fontSize: '20px' });
                        
                        textMetrics.init({
                          fontSize: '14px',
                          lineHeight: '20px',
                          fontFamily: 'Helvetica, Arial, sans-serif',
                          fontWeight: 400,
                          width: 100,
                        });
                        

                        【讨论】:

                          【解决方案25】:

                          您可以使用max-content 来测量文本的像素宽度。

                          这是一个实用功能。它可以选择将任何节点作为上下文来计算宽度,并考虑任何 CSS,如 font-size、letter-spacing 等。

                          function measureTextPxWidth(
                            text,
                            template = document.createElement("span")
                          ) {
                            const measurer = template.cloneNode();
                            measurer.style.setProperty("all", "revert", "important");
                            measurer.style.setProperty("position", "position", "important");
                            measurer.style.setProperty("visibility", "hidden", "important");
                            measurer.style.setProperty("width", "max-content", "important");
                            measurer.innerText = text;
                          
                            document.body.appendChild(measurer);
                            const { width } = measurer.getBoundingClientRect();
                            document.body.removeChild(measurer);
                            return width;
                          }
                          
                          document.querySelector('.spanTextWidth').innerText = 
                            `${measureTextPxWidth('one two three')}px`
                            
                          document.querySelector('.h1TextWidth').innerText = 
                            `${measureTextPxWidth('one two three', document.querySelector('h1'))}px`
                          h1 {
                            letter-spacing: 3px;
                          }
                          <span>one two three</span>
                          <div class="spanTextWidth"></div>
                            
                          <h1>one two three</h1>
                          <div class="h1TextWidth"></div>

                          【讨论】:

                            猜你喜欢
                            • 2010-12-07
                            • 1970-01-01
                            • 2011-11-25
                            • 2012-07-26
                            • 1970-01-01
                            • 2015-02-20
                            • 1970-01-01
                            • 2017-10-21
                            相关资源
                            最近更新 更多