144

When using a fixed width font, I'd like to specify the width of an HTML element in characters.

The "em" unit is supposed to be the width of the M character, so I should be able to use it to specify a width. This is an example:

<html>
  <head>
    <style>
      div {
        font-family: Courier;
        width: 10em;
      }
    </style>
  </head>
  <body>
    <div>
      1 3 5 7 9 1 3 5 7 9 1
    </div>
  </body>
</html>

The result is not what I wanted as the browser line breaks after column 15, not 10:

1 3 5 7 9 1 3 5
7 9 1

(Result in Firefox and Chromium, both in Ubuntu.)

Wikipedia's article says that an "em" is not always the width of an M, so it definitely looks like the "em" unit can't be trusted for this.

Martin Vilcans
  • 5,428
  • 5
  • 22
  • 17
  • 1
    I believe that "en" is also a legal width; it's the width of a digit in typography. That *might* work better for you. – Pete Wilson Nov 18 '11 at 17:34
  • 8
    The 'em' property uses the font-size, or *height*, of the font, not the width of the letters. @Pete: It is not, see [CSS Values and Units Module Level 3](http://dev.w3.org/csswg/css3-values/). – animuson Nov 18 '11 at 17:37
  • Unless you're using a fixed-width font, different characters have different widths. Therefore it's functionally impossible to set a width in terms of number of characters shown. – Emily Nov 18 '11 at 17:50
  • possible duplicate of [How to set width of
    to fit constant number of letters in monospace font?](http://stackoverflow.com/questions/1255281/how-to-set-width-of-div-to-fit-constant-number-of-letters-in-monospace-font)
    – Martin Vilcans Nov 18 '11 at 23:37
  • "This question still needs 4 vote(s) from other users to close" - Hey, it's my question! Let me close it! – Martin Vilcans Nov 18 '11 at 23:38
  • Even if it worked the way you were hoping, it would wrap in your example, because you forgot to count the spaces between your digits. You have 10 digits and 9 spaces, so 19 "characters" required to not wrap. – jkcunningham Mar 26 '22 at 00:52

2 Answers2

313

ch unit

The unit you're looking for is ch. According to the MDN docs:

ch: Represents the width, or more precisely the advance measure, of the glyph "0" (zero, the Unicode character U+0030) in the element's font.

It is supported in current versions of major browsers (caniuse).

Example

pre {
    width: 80ch; /* classic terminal width for code sections */
}
Community
  • 1
  • 1
transistor09
  • 4,828
  • 2
  • 25
  • 33
  • 3
    There's also the [figure space](https://en.wikipedia.org/wiki/Figure_space), which is precisely "equal to the width of one digit" as described in Wikipedia's [space (punctuation)](https://en.wikipedia.org/wiki/Space_%28punctuation%29) article. It's Unicode value is U+2007 and it can be entered in HTML using ` ` or ` `. It's functionally equivalent to the `ch` unit of CSS, but while that isn't widely supported, it can be used as a workaround in HTML (ugly hack, but should work). – waldyrious May 09 '14 at 23:48
  • 2
    Actually, according to [this chromium issue](https://code.google.com/p/chromium/issues/detail?id=196822), Chrome supports it since v27, so right now the latest versions of all the major browsers (IE, Chrome and Firefox) support the ch unit :) – waldyrious May 09 '14 at 23:52
  • 2
    One should note the character size is the size of the glyph '0' in the element's font. If you expect larger characters like 'm' or 'w' you might want to consider expanding accordingly or having it expand as needed (e.g. http://stackoverflow.com/questions/7168727/make-html-text-input-field-grow-as-i-type) – user420667 Mar 29 '16 at 18:13
  • very useful. I added a sample. – Louis Apr 07 '16 at 11:54
  • The ch unit considers the width of the '0' - it doesn't really assure, for example with `max-width: 90ch;` that the lines of text will actually all be less than or equal to 90 characters. –  Apr 27 '16 at 16:47
  • @Willege yes, it would be irresponsible to rely solely on this to make, say, a terminal emulator but, if the font is truly monospaced (at least for the characters in use) and there are no rounding bugs, lines *should* be as long as specified. – transistor09 Apr 27 '16 at 21:35
  • 1
    Yep, no problems with monospaced fonts. –  Apr 28 '16 at 08:50
  • 2
    IE11 supports it wrong. https://stackoverflow.com/questions/17825638/css3-ch-unit-inconsistent-between-ie9-and-other-browsers – aleha_84 Feb 22 '18 at 18:27
  • if you want to use `ch` along with `letter-spacing` a trick is to set width to the amount of characters in `ch` + (letter-spacing * (amount characters - 1)). e.g 5 characters with 1px letter spacing: `letter-spacing: 1px; width: calc(5ch + 4px)`. – Mikel Nov 15 '18 at 09:35
  • This is one issue to consider, if you need to support IE11 there is bug in ch unit, where it's smaller then actual character (because it don't count surrounded spaces), the issue is present since IE9, check [CSS3 ch unit inconsistent between IE9+ and other browsers](https://stackoverflow.com/q/17825638/387194). This can be fixed by using width in JavaScript, If IE is something you support. – jcubic Jul 06 '20 at 21:24
  • Looks at `%`, `em`, `vw`. @transistor90 : "These aren't the units you're looking for" ;) – Aaron Hudon Feb 21 '22 at 00:11
26

1em is the height of an M, rather than the width. Same holds for ex, which is the height of an x. More generally speaking, these are the heights of uppercase and lowercase letters.

Width is a totally different issue....

Change your example above to

<div>
    <span>1</span> 3 5 7 9 1 3 5 7 9 1
</div>

and you will notice width and height of the span are different. For a font-size of 20px on Chrome the span is 12x22 px, where 20px is the height of the font, and 2px are for line height.

Now since em and ex are of no use here, a possible strategy for a CSS-only solution would be to

  1. Create an element containing just a &nbsp;
  2. Let it autosize itself
  3. Place your div within and
  4. Make it 10 times as large as the surrounding element.

I however did not manage to code this up. I also doubt it really is possible.

The same logic could however be implemented in Javascript. I'm using ubiquitous jQuery here:

<html>
  <head>
    <style>
      body { font-size: 20px; font-family: Monospace; }
    </style>
    <script 
      type="text/javascript" 
      src ="https://ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js">
    </script>
  </head>
  <body>
    <div>1 3 5 7 9 1 3 5 7 9 1</div>
    <script>
      $('body').append('<div id="testwidth"><span>&nbsp;</span></div>');
      var w = $('#testwidth span').width();
      $('#testwidth').remove();
      $('div').css('width', (w * 10 + 1) + 'px');       
    </script>
  </body>
</html> 

The +1 in (w * 10 + 1) is to handle rounding problems.

Gerd Riesselmann
  • 986
  • 8
  • 13
  • 2
    I was hoping for a pure CSS solution, which only is possible if you happen to know the ratio between the height and the width of a character (see http://stackoverflow.com/questions/1255281/how-to-set-width-of-div-to-fit-constant-number-of-letters-in-monospace-font). I'm accepting this as the answer as it seems to be a robust solution. – Martin Vilcans Dec 22 '11 at 20:45
  • 1em is not the height of an M according to the answers here http://graphicdesign.stackexchange.com/questions/4035/what-does-the-size-of-the-font-translate-to-exactly?newreg=c0e8d07377164ef992aef80043838507 The "|" character should be closer to 1em. – Sogartar Oct 14 '16 at 11:01
  • 1
    Sogartar, for clarification: in typography proper 1 em is indeed the width (as well as the em height) of a fixed-width character. However, that is "typography proper" and we have many fly-by-night folks out there creating font files which do not adhere to typographic rules — especially true in the case of web fonts. The point of my comment here is not (merely) curmudgeonly grandstanding. My point is: **test, test, test.** (And then test some more.) – Parapluie Dec 06 '16 at 21:42
  • 1
    Please use the 'ch' unit. This answer describes it well: https://stackoverflow.com/a/16586438/244640 – chetbox Jun 16 '21 at 10:13