浏览器字体中每个字符的渲染像素宽度数据

时间:2020-03-06 15:01:50  来源:igfitidea点击:

我有一个表格列,需要将其限制为一定的宽度,例如100像素。有时,该列中的文本宽于此并且不包含空格。例如:

a_really_long_string_of_text_like_this_with_no_line_breaks_makes_the_table_unhappy

我想计算文本服务器端的宽度,并在正确的字符数后添加一个省略号。问题是我没有有关文本渲染大小的数据。

例如,假设浏览器是Firefox 3,字体是12px Arial。字母" a"的宽度,字母" b"的宽度等等是多少?

是否有显示每个字符像素宽度的数据?还是生成它的程序?

我认为聪明的一次性JavaScript脚本可以解决问题。但是,如果有人已经这样做,我不想花时间重新发明轮子。我肯定不是第一个遇到这个问题的人。

解决方案

做服务器端非常非常困难。我们永远无法知道用户安装了哪些字体,并且有很多因素会影响文本的显示。

尝试以下方法:

table-layout: fixed;

这样可以确保表格的大小永远不会超过我们指定的大小。

溢出如何滚动?

这不仅不可能在服务器端进行,而且也没有任何意义。我们不是客户端将使用的浏览器,也不知道客户端的字体设置将覆盖我们分配给HTML的所有样式信息。我们可能会认为我们在样式属性中使用了绝对定位像素,但是客户端可能只是忽略这些像素或者使用某些插件来缩放所有内容,因为客户端使用了高dpi的屏幕。

使用固定宽度通常不是一个好主意。

从根本上讲,这在服务器端是不可能的。除了安装了不同字体的人的问题之外,还需要字距调整(取决于旁边的字母,字母" f"将占用不同的空间)和字体渲染选项(cleartype是否启用?"大字体"?)。

我们可以将文本置于不可见的范围内,并读取宽度范围,但是从根本上来说,这看起来像是在试图破坏网站,因此,我建议禁止发布长度超过特定长度的单词,例如30个字符且不带空格(允许链接更长!-)

-但简单的方法是在表单元格中放置一个块元素:

<td><div style="width:100px;overflow:hidden">a_really_long_string_of_text_like_this_with_no_line_breaks_makes_the_ta ... </div></td>

这将有效地消除混乱的餐桌!

我们无法在服务器端进行任何计算。我们只需要使用浏览器标识字符串即可,该字符串可以正确地告诉我们用户的操作系统和浏览器,也可以不告诉我们。我们也可以"询问"(通过字体标签或者CSS)用于显示文本的特定字体,但不能保证用户已安装该字体。除此之外,用户可能在操作系统级别具有不同的DPI设置,或者可以通过浏览器缩放功能使文本变大或者变小,或者可以完全使用自己的样式表。

Ext JS有一个模块可以做到这一点

TextMetrics
  Provides precise pixel measurements
  for blocks of text so that you can
  determine exactly how high and wide,
  in pixels, a given block of text will
  be.

我确信还有其他可用的库也可以做到这一点。

这是我想到的客户端解决方案。它是我的应用程序特有的,但是如果有人遇到相同的问题,我在这里分享。

它的工作速度比我预期的要快。并且假定单元格的内容是文本,在缩短过程中将仅擦除任何HTML格式的文本。

它需要jQuery。

function fixFatColumns() {
  $('table#MyTable td').each(function() {
    var defined_width = $(this).attr('width');
    if (defined_width) {
      var actual_width = $(this).width();
      var contents = $(this).html();
      if (contents.length) {
        var working_div = $('#ATempDiv');
        if (working_div.is('*')) {
          working_div.html(contents);
        } else {
          $('body').append('<div id="ATempDiv" style="position:absolute;top:-100px;left:-500px;font-size:13px;font-family:Arial">'+contents+'</div>');
          working_div = $('#ATempDiv');
        }

        if (working_div.width() > defined_width) {
          contents = working_div.text();
          working_div.text(contents);
          while (working_div.width() + 8 > defined_width) {
            // shorten the contents of the columns
            var working_text = working_div.text();
            if (working_text.length > 1) working_text = working_text.substr(0,working_text.length-1);
            working_div.text(working_text);
          }
          $(this).html(working_text+'...')
        }

        working_div.empty();
      }

    }
  });

}

如果我们认为这不适用于FireFox,为什么不只使用CSS?表格已固定为table-layout :,相关的列已溢出:隐藏;文本溢出:省略号空白:nowrap。

http://www.css3.info/preview/text-overflow/

这是css3的新功能。

某些用户具有更大或者更小的默认字体设置。我们无法在服务器上执行此操作。我们只能在浏览器呈现页面后对其进行度量。

由于可以在浏览器端轻松更改字体大小,因此很容易使服务器端计算无效。

客户端的快速解决方案是使用溢出属性为单元格设置样式:

td
{
    overflow: scroll; /* or overflow: hidden;  etc. */
}

更好的选择是在服务器端截断字符串,并提供一个简单的JavaScript工具提示,以显示较长的版本。 "扩展"按钮也可能会将结果显示在覆盖div中。

我们想要的是<wbr>标记。这是一个特殊的HTML标记,它告诉浏览器如果需要换行可以在此处打断一个单词。我不会将其插入到文本中进行持久存储,因为那样我们会将数据与显示该数据的位置/方式耦合在一起。但是,完全可以接受将标签服务器端注入以视图为中心的代码中(例如,使用JSP标签或者可能在控制器中)。我就是那样做的。只需使用一些正则表达式来查找比X个字符长的单词,然后将每X个字符将此标记插入到这些单词中。

更新:我正在四处查看,似乎并非所有浏览器都支持wbr。最值得注意的是IE8. 我自己还没有测试过。也许我们可以使用overflow:hidden作为备份或者类似的东西。