[otvar] Computing width for text in variable webfonts

Simon Cozens
Simon Cozens Posts: 752
edited March 2019 in Font Technology
I have been working on a new hyphenation-and-justification engine for variable fonts; you can find the code here and also view a demo site. But I've come across a problem I don't know how to solve.

It works beautifully for some fonts (Skia for instance) but not for others, and I've kind of worked out what the root problem is. I am using the CSS font-stretch property to set the desired width of text to a given percentage. For example, if I have a word which occupies 207 points and for line breaking purposes I need it to occupy 124 points, I set font-stretch to 60%. Now I'm testing using DJR's Fit, which can most certainly compress to 60% of normal and even less, but with font-stretch set to 60%, it still occupies 145 points - the actual compression is 70%.

From my point of view, the browser is misbehaving: I asked for 60% compression, I got 70%. But I wonder if underlying that is the arbitrariness of the extremes of the wdth"axis: Fit has a "skyline" named instance which has a wdth of 0, but it clearly has some width, while its "ultra extended" instance with wdth 1000 is somewhat less than 10 times wider than the regular (which itself has wdth 110!). So the font-stretch property really has no hope of getting it right.

How do I set a piece of text in a variable font to a particular width in a browser?

I guess the dumb-stupid solution is to set a piece of text at font-variation-settings: 'wdth' (whatever the minimum is) and measure it, then at font-variation-settings: 'wdth' (whatever the maximum is) and measure that, and interpolate between the two. But I'm not even sure how to get the minimum and maximum values from the font in a browser. Any ideas?

Comments

  • John Hudson
    John Hudson Posts: 3,244
    I don't see how the compression or expansion value of a proportionally spaced type with a wdth axis can ever be anything other than an approximation, even presuming the font developer has tried to get the axis values as close as possible to percentage adjustments. For any single vertical stem letters such as i and l, the advance width compression adjustment is likely to be less than for wider glyphs in order to maintain consistent stem weight and spacing. The same is true for a lot of punctuation characters. So when you request a 60% font-stretch width from a variable font, the actual compression from the 60 value on the wdth axis is going to depend on the characters in your text.
  • Yeah, the only way to really do it is to set a width value and then measure what comes out. My project Font-To-Width does this by starting in the middle and zeroing in on the value that best fits the available box:

    https://github.com/chrissam42/font-to-width/blob/master/font-to-width.js#L341
  • And to your other question, about how to find the available axis values from the browser, there is no direct way to do so now without using something like opentype.js to load the font and pull the axis values from the fvar and STAT tables. But! the CSS Working Group is discussing adding such an interface to Javascript.
  • I take your point about vertical stem letters, and I am moving more to the conclusion that the only way to set text to a given width is to measure it and fiddle the variation values in CSS until it gets to the width I need it to be. (I would still need to know where the extremities are so I know how "stretchy" the font can be, but I can probably use Opentype.js or something to parse the font file. Maybe.) 

    But here's what the W3G CSS Fonts specification says about font-stretch:
    <percentage> values represent the fractional width of the glyphs.

    If that's what the spec says, it's not unreasonable to think "I set font-stretch to 50%, so the glyphs should be 50% as wide." Arguably the spec is wrong here, but the spec is wrong because it assumes that "declared" width and "actual" width are identical, when as you say, the relationship is more complicated than that.

  • Dave Crossland
    Dave Crossland Posts: 1,431
    Chris, do Font Bureau Parametric Axes with ranges calibrated to Per Mille Of Em help?
  • John Hudson
    John Hudson Posts: 3,244
    edited March 2019
    do Font Bureau Parametric Axes with ranges calibrated to Per Mille Of Em help?
    I don't think they do, because as I've asked numerous times: What is being measured? It's not as if per mille of em transparent width adjustments are increasing the width of each glyph by the same per mille of em quantity, because that, like applying a straight percentage adjustment, this would distort the spacing of narrow vs wide glyphs. As far as I can tell, parametric axes are parametric in terms of affecting individual parameters of glyph opaque (figure) and transparent (ground), not in affecting them in predictably quantifiable way.

    The same is true for weight as for width: an axis adjustment that adds +45 per mille of em to the x opaque of the uprights of an uppercase H likely won't add the same amount of the uprights of a lowercase n, let alone to the upright of a plus sign, and the latter won't share the same x,y behaviour as letters, since the plus sign needs to retain optically equivalent x,y stem weights while the stroke contrast of the letters might change.

    So I still don't see how you can make quantifiable predictions from parametric axes for arbitrary text strings any more than you can using percentage values as in CSS font-stretch, at least for proportionally spaced fonts.
  • John Hudson
    John Hudson Posts: 3,244
    Simon, yes, the CSS spec definition only really works if one is mechanically condensing or expanding a static font, such that weight and width are both being scaled horizontally by a given percentage. As soon as one tries to tie the font-stretch value to either designed widths of an extended font family or to a variable font, the value for an arbitrary run of glyphs becomes more or less approximate.

    At that point, one needs to consider the question what e.g. 60% means. Is it:

    a) the average change to the width of the glyphs to which font-stretch is applied?

    b) the average change to the width of all the non-zero glyphs in the font?*

    c) the change to the width of the bounding box of the text to which font-stretch is applied?

    _____

    * Thought in passing: if (b) were the case, then it would be possible for font makers to design to this standard by making the wdth axis relative to the OS/2 table xAvgCharWidth value. Hmm. I like this idea, although I've not thought it through thoroughly.
  • @Chris Lewis, thank you, that was it. Inspired by your code, I came up with this:

  • Nice!