Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scale fixed-width font to fit constant number of characters on a line

I have a websocket based terminal session. I want the font size to increase to fill the div such that it is always 80 characters wide. What's the best way of doing this? I'd love it if there was a CSS-only way of doing this, but I'm already using jQuery, so a vanilla javascript or jQuery solution would be good too.

like image 463
Phil Lello Avatar asked Jan 18 '15 17:01

Phil Lello


2 Answers

Here's a CSS-only example based on the8472's answer:

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;
}

How does it work?

To get the right font-size, divide 160 by the number of characters you want to fit per line, minus 0.01.

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

Tested in Chrome, FF and safari.

like image 113
Etienne Martin Avatar answered Oct 04 '22 17:10

Etienne Martin


For browsers that support fractional font sizes or CSS text-rendering: geometricPrecision, you can get a fixed-width font to perfectly fit within any bounds.

In this screenshot, the fourth line is exactly 80 characters:

enter image description here

For browsers that don't support fractional font sizes , it is impossible to always make x characters fit within a given width.

Here's the same text with a 12px font:

enter image description here

… and with a 13px font:

enter image description here

Using the 12px font, the longest line is 83 characters, so it's too small. Using the 13px font, the longest line is 77 characters, so it's too large.

In this situation, you must shrink or widen the container to match the font:

enter image description here

The code below places an 80-character wide span in divs of varying widths, using a style of word-wrap: break-word;. It does a binary search for the best font size, using getClientRects() to determine upper and lower bounds for the binary search.

In case the browser doesn't support fractional font sizes, it adjusts the container's width to match the font size.

The span is then removed.

$('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();
});

Tested in Chrome, IE, Firefox, Safari, and Opera.

Fiddle

like image 28
Rick Hitchcock Avatar answered Oct 04 '22 17:10

Rick Hitchcock