0

I'd like to know the .ex value of, say, helvetica at 20px. To put it another way, in the web page below, what would be the ex value of "Hello", in pixels? (And more generally, how to do this for an arbitrary font at an arbitrary size?)

<html>
  <head>
    <style>
      body {
        font-family:Helvetica;
        font-size:20px;
      }
    </style>
  </head>
  <body>
    Hello
  </body>
</html>

===========

For example, after some convoluted approach using MathJax's SVG output mode (that specifies the height of the SVG in ex with respect to the surrounding page's font) I found that the ex value of Helvetica at 20px is something quite close to

10.467px

(safari and chrome both), while the ex value of Helvetica at 21px is something close to

10.982px

(again, safari and chrome both), and so on. These numbers seem to be independent of any other parameters besides the font and its size. So how to get them?

Since my method of getting these ex-values is really convoluted, and I am not obtaining the "official" ex value of the font, but rather a reverse-engineered ex value, I would like to know a non ad-hoc way of getting the "official" ex value.

jhpratt
  • 6,841
  • 16
  • 40
  • 50
Labrador
  • 623
  • 7
  • 13
  • I don't think that there is a uniform measurement of pixel equivalence for a relative unit. You could find it out per device, client-side, using JavaScript but without knowing your requirements and what you're trying to do it's hard to post any kind of an answer without making assumptions and guesses. – David Thomas Apr 04 '18 at 10:57
  • This question may help: https://stackoverflow.com/questions/918612/what-is-the-value-of-the-css-ex-unit By the way, as I wrote elsewhere, the information is contained in the font, that is, it's stored somewhere in the font file, and it's different for each font. So there is no equation. There is a little trick called `font-size-adjust` which you may be able to make use of - basically it allows you to set your own `ex` size. But beware that it currently does not work in IE or Edge. – Mr Lister Apr 04 '18 at 12:56
  • @DavidThomas Given a font-family and a font-size, I think the value of "ex" is uniquely defined in pixels, yes. See my edit. (And it's this number of pixels I want.) – Labrador Apr 06 '18 at 02:27
  • @MrLister I'm happy to go look at the font file. Can you tell me where to find it, and what to look for? – Labrador Apr 06 '18 at 02:29
  • @MrLister OK but that approach requires a manual binary search to get the block size right. (The approach based on MathJax means inspecting some files, but at least no binary search.) I'll poke around a little more and let you know if I find anything... – Labrador Apr 07 '18 at 02:22
  • @MrLister Thanks for the clarification, and I think FontMetrics should be the accepted answer. (And why not use your other answer with fontSize = '20px' instead of 1000px?) If you post your comment as an answer I'll be glad to accept it... (and it would be great if someone removed that pesky downvote, haha) – Labrador Apr 08 '18 at 01:21
  • OK, I posted an answer, where I also explain why 1000px and not 20px. Can't do anything about the downvote, but here's an upvote instead. – Mr Lister Apr 08 '18 at 19:49

1 Answers1

1

One way, without using any external libraries, is to create a block with a height of 1ex and measure how high it is.

var div = document.createElement('div'); div.style.fontSize = '1000px';
div.style.height = '1ex';
document.body.append(div);
var xHeight = div.scrollHeight;
document.body.removeChild(div);

console.log('1ex = 0.'+xHeight+'em');

The problem with this method though is that the result is rounded to whole pixels; so if you do this with a font size of 20px, you would get 10px rather than the 10.467 you got. That's why I used 1000px, so the result does have at least some precision.

Another way is making use of a library such as FontMetrics. From their main page:

<script src="FontMetrics.min.js" type="text/javascript"></script>
const metrics = FontMetrics({
  fontFamily: 'Roboto',
  // Optional (defaults) 
  fontWeight: 'normal',
  fontSize: 200,
  origin: 'baseline'
})

console.log('1ex = '+(-metrics.xHeight)+'em');

(Can't make a live snippet of this example, because their JS file does not have a CDN. But I downloaded and tested the JS file and it works.)

Mr Lister
  • 45,515
  • 15
  • 108
  • 150