What could be an effective strategy for handling frac/tions in OpenType fonts?
I couldn’t find any previous discussions on this topic.
Is there a preferred method for implementing the OpenType 'frac' feature?
Lately, I’ve been using the following code. (In a publication I have never used fractions with more than four digits either in the numerator or in the denominator.)
@nums = [zero one two three four five six seven eight nine];
@numr = [zero.numr one.numr two.numr three.numr four.numr five.numr six.numr seven.numr eight.numr nine.numr];
@dnom = [zero.dnom one.dnom two.dnom three.dnom four.dnom five.dnom six.dnom seven.dnom eight.dnom nine.dnom];
feature frac {
sub slash by fraction;
} frac;
feature locl {
sub @nums' @nums @nums @nums @nums @nums @nums @nums @nums @nums fraction by @numr;
sub @nums' @nums @nums @nums @nums @nums @nums @nums @nums fraction by @numr;
sub @nums' @nums @nums @nums @nums @nums @nums @nums fraction by @numr;
sub @nums' @nums @nums @nums @nums @nums @nums fraction by @numr;
sub @nums' @nums @nums @nums @nums @nums fraction by @numr;
sub @nums' @nums @nums @nums @nums fraction by @numr;
sub @nums' @nums @nums @nums fraction by @numr;
sub @nums' @nums @nums fraction by @numr;
sub @nums' @nums fraction by @numr;
sub @nums' fraction by @numr;
sub fraction @nums' by @dnom;
sub fraction @dnom @nums' by @dnom;
sub fraction @dnom @dnom @nums' by @dnom;
sub fraction @dnom @dnom @dnom @nums' by @dnom;
sub fraction @dnom @dnom @dnom @dnom @nums' by @dnom;
sub fraction @dnom @dnom @dnom @dnom @dnom @nums' by @dnom;
sub fraction @dnom @dnom @dnom @dnom @dnom @dnom @nums' by @dnom;
sub fraction @dnom @dnom @dnom @dnom @dnom @dnom @dnom @nums' by @dnom;
sub fraction @dnom @dnom @dnom @dnom @dnom @dnom @dnom @dnom @nums' by @dnom;
sub fraction @dnom @dnom @dnom @dnom @dnom @dnom @dnom @dnom @dnom @nums' by @dnom;
}
Additionally, with this approach, simply adding the 'fraction' character #2044 automatically creates a fraction.
Comments
-
Not all fonts include a frac feature, and those that do often implement it in various ways. According to the OpenType specification, the frac feature is designed to replace figures (digits) separated by a slash (U+002F) or a fraction slash (U+2044) with “common” (diagonal) fractions.
So, the frac feature should only target digits involved in actual fractions. This ensures that whole numbers and slashes used in other contexts (such as measurements or mathematical operations) remain unaffected. A robust frac implementation should support compound fractions. For example:
<frac>4 5/8</frac>
In this case, the frac feature should format the 5/8 as a proper fraction without altering the preceding 4. This maintains the integrity of the whole number while correctly displaying the fraction.
One of the more common ways to implement the frac feature is as follows:
@figures = [zero one two three four five six seven eight nine]; @figuresNumerator = [zero.numr one.numr two.numr three.numr four.numr five.numr six.numr seven.numr eight.numr nine.numr]; @figuresDenominator = [zero.dnom one.dnom two.dnom three.dnom four.dnom five.dnom six.dnom seven.dnom eight.dnom nine.dnom]; @slash = [slash fraction]; feature frac { sub @figures by @figuresNumerator; sub [@slash @figuresDenominator] @figuresNumerator' by @figuresDenominator; sub slash by fraction; } frac;
While this method effectively formats fractions, it can inadvertently affect non-fractional digits and slashes within text blocks. For example:
To address this issue, we can use a more precise method that only affects actual fractions, leaving other parts of the text untouched. One effective approach is using GSUB LookupType 8 (Reverse Chaining Contextual Single Substitution), a technique we developed in June 2021.
@figures = [zero one two three four five six seven eight nine]; @figuresNumerator = [zero.numr one.numr two.numr three.numr four.numr five.numr six.numr seven.numr eight.numr nine.numr]; @figuresNumeratorEx = [fraction @figuresNumerator]; @figuresDenominator = [zero.dnom one.dnom two.dnom three.dnom four.dnom five.dnom six.dnom seven.dnom eight.dnom nine.dnom]; @figuresDenominatorEx = [fraction @figuresDenominator]; feature frac { sub @figures slash' @figures by fraction; rsub @figures' @figuresNumeratorEx by @figuresNumerator; sub @figuresDenominatorEx @figures' by @figuresDenominator; # Optional smaller space between whole number and fraction: sub @figures space' @figuresNumerator by space.frac; } frac;
Hope this help.3 -
0
-
Erwin’s advice is good. I would only add that the frac feature should only ever be applied to discrete fraction strings, which is why I don’t think his second method is needed: the frac feature should not be applied across a whole document in the hope that it will only, contextually affect fractions. If a user wants to do that, it is better to do so at the character style settings level in an application, rather than relying on the font getting it right at the glyph processing level (and then getting it wrong if you change fonts).Additionally, with this approach, simply adding the 'fraction' character #2044 automatically creates a fraction.That depends on the shaping engine and application environment. The HarfBuzz shaping engine introduced that mechanism, in which U+2044 is used as a trigger for a character level identification of a fraction string, to which the frac feature is then applied (actually, I think it may apply the numr and dnom features on either side of the fraction slash). It is clever, and consistent with how Unicode defines U+2044, but I think not all shaping engines have implemented this, so you will find different results in different environments, even with the same font.1
-
Agree with John.
People formatting huge swathes of text with “fractions on” are asking for all sorts of other trouble, as things like dates expressed with slashes will turn into fractions (e.g. 9/11).1 -
While I agree that global formatting of text blocks with the <frac> feature is fraught, you can solve the “date” problem (if not 9/11), with this code at the beginning of your feature:
ignore sub slash' @figures @figures slash; ignore sub slash @figures @figures slash'; ignore sub slash' @figures slash; ignore sub slash @figures slash';
1 -
For clarification, dates in the format such as today’s 12/27/24.0
-
I don’t agree unconditionally with John & Thomas. If the text environment is variable or fluid, then yes, applying fractions globally can be fraught. But if you’re typesetting a cookbook, then having a {frac} feature that you can turn on globally (if not document-wide, then at least universally within a paragraph style), without having to somehow identify discrete fraction strings, is a huge production boost.I designed my share of cookbooks when I worked actively as a book designer. Which is why I prompted Tal Leming to develop his “fraction fever” code. (Which subsequently led to the improved and more robust “fraction fever 2”.)I do agree that the user should be aware of the potential edge cases and act accordingly. As with any discretionary feature that you choose to apply globally.
4 -
I think typesetting a cookbook is exactly where I would want fractions to be tagged as such and definitely not left to the font to automatically get right. I would want a way to distinguish numeral characters involved in fractions from nearby whole numbers in markup.
Put another way: the contextual rules required to be implemented in GSUB to affect reliable global fraction identification at the font level can be applied in GREP styles at the document level, and then are available to any font with a basic frac implementation.0 -
As something of a traditionalist, I’ve always like nut (stacked) fractions.
I was never able to figure out a comprehensive code for assembling them on the fly in the <frac> feature, but in several typefaces I simply pre-composed nut fractions for half, quarters, thirds and eighths, which actually all have their own Unicode points, and are really all that typographers need unless they’re typesetting engineering/construction stuff with sixteenths and thirtyseconds, or maths, for which they would require a full-on math font anyway.
Thirds—for news about incomplete baseball innings!0 -
John Hudson said:I think typesetting a cookbook is exactly where I would want fractions to be tagged as such and definitely not left to the font to automatically get right. I would want a way to distinguish numeral characters involved in fractions from nearby whole numbers in markup.
Put another way: the contextual rules required to be implemented in GSUB to affect reliable global fraction identification at the font level can be applied in GREP styles at the document level, and then are available to any font with a basic frac implementation.That would indeed be a more robust and agnostic approach. Ideally, I’d personally prefer to see explicitly encoded text. As Nick says, all of the cookbook fractions have Unicode codepoints.But all of that is assuming a level of text [pre]production much more sophisticated than most publishing environments that I’ve worked with. (And certainly more than our copyeditors were prepared to do in the mid 2000s.)So our different experiences provide different perspectives and approaches. 😉
1 -
@Nick ShinnI’ve always like nut (stacked) fractions. I was never able to figure out a comprehensive code for assembling them on the fly in the <frac> feature...Nutso is is pretty robust, so long as the user doesn’t apply tracking to the results.
1 -
@Nick Shinn I figured out how to do automated nut fractions, but never ended up using it in a font. The problem is that there's no way to center the denominators. It's possible to do a lopsided version.
Let's say you want to allow a max of four numerators. Make three copies of the numerators and give them classes like @nums @nums.1@nums.2 @nums.3 Make one copy of the denominator @dnom @dnom.1. For the fraction bar, make 4 variants as well.
After the first numerator, check to the left and change it to the next alternate. For the slash, check the class of the preceding digit and substitute it for one of the fraction bar variants. Each of the four fraction bars will have a specific negative sidebearing which will align the denominator under the left side of the bar.
But what if the denominator has more digits than the numerator? The @dnom.1 variants include their own little fraction bar above each digit. They'll overlap the existing fraction bar and extend it.
But I can't think of a way to center everything. It doesn't seem possible because I don't think the numerator can “know” how long the denominator will be.
1 -
As Thomas undoubtedly remembers, at Adobe we initially developed a global, contextual approach to the frac feature, but after a short while we realized it was ill-advised. (It seemed very cool and fun to do it that way, but then reality set in.) The “tagged text” approach @John Hudson” is describing is what I would recommend.
1 -
Ray, take a look at the Nutso (and Nutso2) implementations I linked to above. These are able to handle arbitrary combinations of numerators and denominators—up to ten of each, if I recall correctly—with both centered on the bar length. Nutso2, can also handle sequences of longer numerators than denominators.
I can’t actually remember all the details of how I did it, but the important thing is to be able to mark at the glyph level where the fraction begins, and then contextually track everything else relative to that point. It looks like you were trying to do it all with GSUB, which is why you ran into trouble getting uneven lengths of numerators and demoninators aligned. The Nutso method uses contextual GPOS (which means, of course, that the code provided has to be updated if your numr and dnom glyphs are different widths).1 -
I’ve never shipped a font using the Nutso method for European nut fractions—mostly because no client ever asked for them—, but I did use it for Burmese stacked fractions in the Myanmar Text font for Microsoft.
1 -
John Hudson said:Erwin’s advice is good. I would only add that the frac feature should only ever be applied to discrete fraction strings, which is why I don’t think his second method is needed: the frac feature should not be applied across a whole document in the hope that it will only, contextually affect fractions. If a user wants to do that, it is better to do so at the character style settings level in an application, rather than relying on the font getting it right at the glyph processing level (and then getting it wrong if you change fonts).John Hudson said:Additionally, with this approach, simply adding the 'fraction' character #2044 automatically creates a fraction.That depends on the shaping engine and application environment. The HarfBuzz shaping engine introduced that mechanism, in which U+2044 is used as a trigger for a character level identification of a fraction string, to which the frac feature is then applied (actually, I think it may apply the numr and dnom features on either side of the fraction slash). It is clever, and consistent with how Unicode defines U+2044, but I think not all shaping engines have implemented this, so you will find different results in different environments, even with the same font.
The OP used the locl feature, which is typically misapplied in this context. However, if it works, it allows the feature to function independently of the shaping engine, provided the engine supports the default Localized Forms feature.
0 -
Around the same time John was developing Nutso, I also worked out a fairly reliable approach using only GSUB. Because GPOS handling in apps still seemed a little iffy back then.My approach could also accommodate larger numerators over smaller denominators. I only developed the proof-of-concept code to up to three-over-three.It requires a set of nut numr/dnom figures all on the same set width. The only variant glyphs are a set of different length fraction bars. So accommodating longer numerator/denominator would only require calculating additional fraction bars.I started writing a Python script to automate all the parts, but didn’t complete it, because we decided not to try to implement in Big Caslon. (Which is why I embarked on the idea in the first place; Matthew’s original design had a set of precomposed nut fractions and I thought arbitrary nut fractions would be cool).2
-
It requires a set of nut numr/dnom figures all on the same set width. The only variant glyphs are a set of different length fraction bars. So accommodating longer numerator/denominator would only require calculating additional fraction bars.That’s the same approach as Nutso2, in terms of the glyphs required. How do you handle the different alignments, though, if only relying on GSUB?
[The original Nutso is simpler—the bar is incorporated into the dnom glyphs, so I only need to worry about the positioning of the numr glyphs—but can’t handle top-heavy fractions.]
0 -
[Of course, the other way to handle this in a cookbook is to use grams amd millilitres like a sane person. ]1
-
John Hudson said:How do you handle the different alignments, though, if only relying on GSUB?You know what, I misspoke. I dug back into that demo code, and indeed I did put in some contextual GPOS to handle the mismatched numr/dnom.I think I had an earlier version with an alternate set of offset numr/dnom glyphs and some complex kerning that almost did it all with GSUB only. (Of course, technically kerning is GPOS; but you know what I mean.)But that approach required more variant glyphs than made practical sense.It was the reliance on non-kerning GPOS that made us decide not to deploy with Big Caslon, since support was sketchy. MC didn’t think it was worth pushing the envelope at that time.I think some environments still don’t like it when a feature calls both GSUB and GPOS rules. Or are we all past that now?
0 -
I think some environments still don’t like it when a feature calls both GSUB and GPOS rules. Or are we all past that now?Alas, I think it is still wise to avoid that. But generally, one can split GSUB and GPOS operations across different features to achieve a singular effect, so long as all the involved features will always be applied together. So the Nutso implementation does GSUB in the afrc feature, and then looks after GPOS in the kern* and mark features.
* The dist feature would also be a good candidate for the nut fraction kerning element.
1 -
Erwin Denissen said:John Hudson said:Erwin’s advice is good. I would only add that the frac feature should only ever be applied to discrete fraction strings, which is why I don’t think his second method is needed: the frac feature should not be applied across a whole document in the hope that it will only, contextually affect fractions. If a user wants to do that, it is better to do so at the character style settings level in an application, rather than relying on the font getting it right at the glyph processing level (and then getting it wrong if you change fonts).2
-
What you describe, Erwin, is typesetting. A font should provide a typesetter with tools to do the job, but shouldn’t always try to automate that job at the glyph processing level, because the typesetter might have different ideas, or might be following a house or series style. That is why I think things like identifying fractions and spacing them relative to whole numbers is properly done at the document style level where, again, it can work with any font with a basic frac feature.4
-
A font that includes a fraction feature such as Tal’s or Erwin’s does not preclude a publisher or typesetter from doing exactly as you suggest — preparing a document by identifying discrete fraction strings and applying the font’s {frac} feature at a document style level so that “it can work with any font with a basic frac feature”.With respect, I think you are conflating recommendations for document processing and for feature code. If the fraction feature Erwin & I advocate *required* it to be applied globally in order to work, that would be one thing. But it doesn’t. If it is applied discretely, as you advocate, then it performs as any other.You seem to be arguing that since the best way to handle fractions in a document is to tag them and only apply the fraction feature to the target string, then that is the only way that a {frac} feature code should work, that one should not have a {frac} that could potentially be applied globally in 90+% of circumstances, caveats acknowledged.Granted, the adjustment of a space.frac between whole number and fraction is a grey area. I would certainly not advocate obliterating the space altogether. Nor should the space be replaced with a differently encoded space.But this substitution is not significantly different than a contextual kern; nor does this spacing judgment strike me as substantively different than other spacing judgments that type designers make, such as whether to include a triplet kern for “f-space-A”, how to space “L-apostrophe-A”, or how to space “quoteright-quotedblright”, etc. Typesetters may always have different ideas (just ask Charles Ellertson).If the typesetter does not like my type designer judgment on this, then don’t apply the fraction feature globally. As you recommend against, regardless. I don’t think that necessarily invalidates this approach to the feature code.0
-
You seem to be arguing that since the best way to handle fractions in a document is to tag them and only apply the fraction feature to the target string, then that is the only way that a {frac} feature code should work, that one should not have a {frac} that could potentially be applied globally in 90+% of circumstances, caveats acknowledged.Yes, that is exactly what I am arguing. Whenever we are dealing with digital typography, we are dealing with the character/glyph distinction and two areas of operations, and I think solutions should be applied in the most appropriate area of operation. OpenType Layout glyph processing is not designed to do things like identify text content strings at the document level, so while it can be hacked to do that for a particular purpose in ‘90+% of circumstances—i.e. <100% of circumstances—that is not a good argument for doing so.
I don’t think contextual kerning is a good parallel, because a) it is an explicitly glyph level operation with no character level parallel and b) the kern feature is intended to be active by default across a body of text, while the frac feature is intended to affect only discrete elements within that text.
0 -
Another comparison is “smart quotes,” which, despite failing in certain apostrophe situations (e.g. rock ’n’ roll) are tolerated because they work well most of the time.
However, smart quotes are applied by default in many applications, which is very wrong according to John’s theory, and I agree. At least <fractions> is discretionary.1 -
However, smart quotes are applied by default in many applications, which is very wrong according to John’s theory...No, that is not what I said at all. ‘Smart quotes’ substitution is applied at the character level, which is entirely appropriate, and possible because character string analysis and manipulation is much more powerful and flexible than GSUB glyph processing (it can even handle things like mirrored punctuation in complex levels of nested bidirectional text). Whether such substitution should be applied by default in an application is sort of moot in terms of what I am saying about the appropriate area of operations.
0 -
John Hudson said:
I don’t think contextual kerning is a good parallel, because a) it is an explicitly glyph level operation with no character level parallel and b) the kern feature is intended to be active by default across a body of text, while the frac feature is intended to affect only discrete elements within that text.Here are two different lookups. One is a GSUB like that found in Erwin’s and Tal’s {frac} features; the second is a GPOS contextual kern:(I’m posting this as an image because I can’t for the life of me figure out how to easily & sensibly format code on TD. 🤨)Can we agree that both of these are equivalent & technically valid means of achieving the same objective of narrowing the space between a whole number and fraction?If so, then- Are you objecting to the whole notion of the type designer adjusting that particular spacing relationship? (because we shouldn’t “try to automate the job” of the typesetter), or
- Are you objecting to doing so with a substitution, rather than using positioning? or
- Are you objecting to having this adjustment registered in a {frac} feature (which is “intended to affect only discrete elements within [a] text”), rather than in some other feature like {kern} or {calt} (which is “intended to be active by default across a body of text”)?
(Note that in one case the type designer’s judgment is easily avoided by not applying the feature broadly, whereas in the other case this adjustment is applied by default and not easily overridden by the typesetter. The former seems more desirable to me, assuming it is a legitimate spacing judgment for the type designer to exercise.)0 -
My primary objection in this discussion has been to trying to use contextual OTL processing to identify fractions at the glyph level, rather than identifying them at the text level. Simply put, I think identifying, itemising and run-segmenting fractions is obviously a character level operation, the application of which allows for relatively simple frac feature coding that only needs to take into account what is included in the fraction run. [A parallel would be something like trying to use contextual OTL to identify the syllabic breakpoint in German compound words at which to disable a ligature. That is obviously much harder than correctly identifying fractions >90% of the time, but the difficulty doesn’t distinguish them: they’re both examples of trying to do something at the glyph level that can be much more reliably done at the character level.]
Regarding, the spacing between adjacent whole numbers and fractions, there are various ways in which this can be addressed, including both character level and glyph level options, as the typographer may prefer. I think it is over-extending the font maker’s responsibility to automate it at the font level, rather than as something a typesetter handles via e.g. a GREP style in the typesetting. I have a lot of cookbooks that involve whole number plus fraction sequences, and observe a lot of different conventions in their spacing. Decisions are being made about how to set this kind of content, so I think it makes sense to leave those decisions to the typographers and typesetters. If a client were to request a custom font that implemented a particular spacing decision for this content, I would probably implement it in the kern feature, a) because that’s what a spacing adjustment is, and b) because I don’t think the frac feature should be expected to be applied to something other than the fraction.0 -
John Hudson said:The HarfBuzz shaping engine introduced that mechanism, in which U+2044 is used as a trigger for a character level identification of a fraction string, to which the frac feature is then applied (actually, I think it may apply the numr and dnom features on either side of the fraction slash).
2
Categories
- All Categories
- 43 Introductions
- 3.7K Typeface Design
- 806 Font Technology
- 1.1K Technique and Theory
- 622 Type Business
- 446 Type Design Critiques
- 543 Type Design Software
- 30 Punchcutting
- 137 Lettering and Calligraphy
- 84 Technique and Theory
- 53 Lettering Critiques
- 489 Typography
- 304 History of Typography
- 115 Education
- 70 Resources
- 500 Announcements
- 80 Events
- 105 Job Postings
- 149 Type Releases
- 165 Miscellaneous News
- 271 About TypeDrawers
- 53 TypeDrawers Announcements
- 117 Suggestions and Bug Reports