缩放固定宽度字体以适合一行上的常量字符数

时间:2015-01-18 17:42:21

标签: javascript jquery html css

我有一个基于websocket的终端会话。我希望增加字体大小以填充div,使其总是80个字符宽。这样做的最佳方法是什么?我喜欢它,如果只有CSS的方式,但我已经使用了jQuery,所以一个普通的javascript或jQuery解决方案也会很好。

7 个答案:

答案 0 :(得分:4)

对于支持小数字体大小或CSS text-rendering: geometricPrecision的浏览器,您可以获得固定宽度的字体,以完全适合任何范围。

在此屏幕截图中,第四行正好是80个字符:

enter image description here

对于不支持小数字体大小的浏览器,不可能始终使 x 字符符合指定的宽度。

这里的文字与12px字体相同:

enter image description here

...并使用13px字体:

enter image description here

使用12px字体,最长的行是83个字符,所以它太小了。使用13px字体,最长的行是77个字符,所以它太大了。

在这种情况下,您必须缩小或扩展容器以匹配字体:

enter image description here

下面的代码使用word-wrap: break-word;样式在宽度不同的div中放置一个80个字符的宽跨度。它使用getClientRects()进行二进制搜索以获得最佳字体大小,以确定二进制搜索的上限和下限。

如果浏览器不支持小数字体大小,它会调整容器的宽度以匹配字体大小。

然后移除范围。

$('div').each(function() {
  var x= $('<span>'+Array(80).join('x')+'</span>').appendTo(this),
      lo= 0.1,
      hi= 50,
      mid;
  do {
    mid= (lo+hi)/2;
    $(this).css({
      fontSize: mid
    });
    if(x[0].getClientRects().length > 1) {
      hi= mid;
    }
    else {
      lo= mid;
    }
  } while(Math.abs(hi-lo)>0.001);
  while(x[0].getClientRects().length === 1) {
    $(this).css({
      width: '-=1'
    });
  }
  while(x[0].getClientRects().length === 2) {
    $(this).css({
      width: '+=1'
    });
  }
  x.remove();
});

在Chrome,IE,Firefox,Safari和Opera中测试过。

Fiddle

答案 1 :(得分:4)

这是一个基于CSS的示例,基于the8472的回答:

div,textarea{
    width:100%;
    max-width: 100%;
    box-sizing: border-box;
    -moz-box-sizing: border-box;
    font-family:  "Lucida Console", Monaco, monospace;
    font-size: 1.99vw; /* The text overflows in safari using (int)2 */
    white-space: nowrap;
    overflow-x:hidden;

    /* styling */ 
    background:#09f;
    min-height: 100px;
    margin-bottom: 30px;
}

它是如何运作的?

要获得正确的字体大小,请将160除以每行所需的字符数减去0.01。

http://jsfiddle.net/mb2L4mee/1/

在Chrome,FF和Safari中测试过。

答案 2 :(得分:2)

一种方法是计算固定font-size的80字符行的大小,并在resize事件上注册函数,以根据终端大小调整font-size。< / p>

<div id="terminal">
    <div class="text">
        Some text
    </div>
</div>

function scale(lineWith) { /* lineWidth based on 80char 10px font-size */
    var ratio = $('#terminal').width() / lineWith;
    $('.text').css('font-size', (10 * ratio) + 'px');
}
$(window).resize(function(){
    scale(lineWith)
});

演示:http://jsfiddle.net/44x56zsu/

这似乎在Chrome(Versión39.0.2171.99m)中调整得相当不错

但我认为不可能将font-size调整为适合所有浏览器的容器大小,因为小数值是四舍五入的。 字体大小测试:http://jsfiddle.net/ahaq49t1/

Font size test result

某些浏览器中的此舍入问题会阻止使用字体属性进行精确调整。

答案 3 :(得分:1)

在纯粹的CSS中,它可能是有限的。如果您知道div将占据视口的分数,则可以根据视口宽度缩放字体。

.terminal {font-size: 1vw;}会导致字体大小(垂直)相当于视图端口的1%。由于等宽字体也具有固定的宽高比,因此宽度取决于字体的宽高比和视口大小。

答案 4 :(得分:1)

不确定这是否是最优雅的解决方案,它还需要更多的抛光。但你可以测量字体。创建一个隐藏的度量栏,以查看字体的宽度(以像素为单位)。 填充所需数量的字符(此处使用20作为演示目的):

<span id="measureBar">12345678901234567890</span>

继续增加测量条的字体大小,找到仍然不比div宽的最大宽度:

$(
  function() {
    var $measureBar = $('#measureBar');
    var $console = $('#console');
    $measureBar.css('font-size', '1px');
    for (i = 1; $measureBar.width() <= $console.width(); i++) {
      $measureBar.css('font-size', i + 'px');
    }
    $console.css('font-size', (i - 1) + 'px');
  }
)
#console {
  background-color: black;
  color: white;
}
#measureBar {
  display: none;
}
#measureBar,
#console {
  font-family: courier;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span id="measureBar">12345678901234567890</span>
<div id="console">12345678901234567890 Text that should be twenty characters wide.</div>

答案 5 :(得分:0)

我面临着非常相似的要求,并提出了一个相当直接的解决方案。一旦我得到一些停机时间,我就会围绕这个示例代码编写一个jQuery插件。

正如其他一些答案中所提到的,关键是使用em作为字体大小的单位。此外,要在所有(现代)浏览器中实现类似的布局,对于必须处理各种固定宽度字体的解决方案,标尺方法是我找到的最可靠的方法。

&#13;
&#13;
function fixieRemeasure() {
    var offset =  document.getElementById("fixie").offsetWidth,
        ruler = (document.getElementById("fixieRuler").offsetWidth * 1.01),
        fontSize = (offset / ruler);   
    document.getElementById("fixie").style.fontSize = fontSize + "em";     
}

function fixieInit(columns) {
    document.getElementById("fixieRuler").innerText = 
            new Array(columns + 1).join("X").toString();
    fixieRemeasure();
}

(function () {
    fixieInit(80); 
    window.onresize = function () { fixieRemeasure(); };       
} ());
&#13;
#fixie {
    padding: 0 2px 0 6px;
    font-size: 1em;
    background-color: #000;
    color: #0F0;
}

#fixieRuler {
    font-size: 1em;
    visibility: hidden;
}
&#13;
<code id="fixieRuler"></code>

<div id="fixie">
<pre>+------------------------------------------------------------------------------+
|                                                                              |
|                   ,%%%,                                                      |
|                 ,%%%` %==--                                                  |
|                ,%%`( '|                                                      |
|               ,%%@ /\_/                                                      |
|     ,%.-"""--%%% "@@__                                                       |
|    %%/             |__`\                                                     |
|   .%'\     |   \   /  //                                                     |
|   ,%' >   .'----\ |  [/                                                      |
|      < <<`       ||                                                          |
|       `\\\       ||                                                          |
|         )\\      )\                                                          |
| ^^^jgs^^"""^^^^^^""^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^        |
|          ASCII Art: http://www.chris.com/ascii/index.php?art=animals/horses  |
+------------------------------------------------------------------------------+</pre>
</div>
&#13;
&#13;
&#13;

这只是一个概念证明,并且有一些相当明显的问题。主要是,resize方法被连续调用,应该用onResizeEnd之类的东西替换,并在之前正确附加到DOM生产用途。要组件化,我使用类选择器而不是id,并且还可以动态地插入/移除标尺元素。

希望它有所帮助。

<强>更新

我根据此示例代码创建了一个新项目fixie.js on github。在性能和模块化方面还有一些工作要做,但它在所有浏览器中运行良好,我相信它提供了最简单的方法,用最少的样板代码来解决问题。

唯一的要求是为em中的pre元素设置font-size,并为其提供格式为&#39; fixie_ COLS &#39;:<的类名称/ p>

<pre class="fixie_80">I'll be 80 columns</pre>

jQuery&amp;要遵循的webcomponent实现。它获得了麻省理工学院的许可,欢迎任何贡献:https://github.com/dperish/fixie.js

答案 6 :(得分:0)

这可以使用纯css使用 vw (视口宽度), vh (视口高度), vmin (相对于宽度)来完成或高度,以较小者为准), vmax (相对于宽度或高度,以较大者为准)长度单位。

对于浏览器兼容性,您可以查看this

对于简单的教程检查this