You can use the selnolig package to break up inappropriate ligatures automatically. For example, 'leaflet' should arguably not have an fl-ligature, and this can be prevented with \nolig{leaflet}{leaf|let}. But with many fonts, breaking this ligature (with selnolig) still does not prevent the f from touching the l. I even tried kerning the fl pair with fontforge, but it seems that selnolig does not use the font's kerning. The following will print 'leaflet' in increasing levels of appropriateness (I think; is it not a rule of typography that letters that do not form ligatures should not touch?).






enter image description here

How could I get the last result without the explicit kern?

PS. This way of breaking the fl-ligature can be seen in Nietzsche, Werke in drei Baenden, Carl Hanser Verlag, 1977:

enter image description here

  • Comments are not for extended discussion; this conversation has been moved to chat. – Joseph Wright Sep 1 '17 at 16:07
  • 1
    The screenshot, to me, is a vivid reminder of how bad typography could be in the 19 century. I see inconsistent irregular interword spacing and poor kerning galore... Oh, and I see way too much whitespace between "f" and "l" in "Verzweiflung"... – Mico Sep 1 '17 at 22:07
  • Please clarify what you mean by "it seems that selnolig does not use the font's kerning". (I'm afraid I have no idea what this is supposed to mean.) – Mico Sep 1 '17 at 22:10
  • @Mico, I meant that changing the font's kerning of fl so that they would not touch had no effect. – Toothrot Sep 1 '17 at 22:34
  • 1
    @Toothrot - selnolig's \nolig macro works by inserting a so-called "whatsit" (not my term!) between the f and l characters. This prevents ligation -- which, after all, is the whole reason for doing this. A side-effect is that because the f and l characters are no longer directly adjacent, the kerning algorithm cannot kick in and insert a custom kern. (If the whatsit were removed in order to allow kerning, the fl ligature would show up once again. Gah!) – Mico Sep 1 '17 at 22:51

I don't think you would ever do this in English but in other languages with a fondness for compound words it is more of an issue.

enter image description here


function breaklig (s)
'leaflet','leaf\string\\kern.5em let'),
'shelfful','shelf\string\\kern.5em ful')
luatexbase.add_to_callback('process_input_buffer',breaklig,'break ligatures in specified words')

I once wrote a leaflet that (or was it a pamphlet) that had a flipped flyleaf.
Actually I have a shelfful of them.

| improve this answer | |
  • 1
    What if I have a macro \leaflet or \begin{leaflet} to typeset leaflets containing the word »leaflet«? – Henri Menke Sep 1 '17 at 9:20
  • 1
    @HenriMenke either don't do that:-) or work harder on the replacement patterns for example you could make the pattern check that the character before the first letter in the word was not \ or { or (simpler) first to a replacement changing \leaflet to ZZZ then add the kerns then change ZZZ back to \leaflet. None of that is hard just tedious – David Carlisle Sep 1 '17 at 9:25
  • 2
    I'd use pre_linebreak_filter and walk all the nodes until I find the sequence leaftlet then back up and insert the kern. That does not break macro parsing. – Henri Menke Sep 1 '17 at 10:08
  • 1
    (+1) for 'I don't think you would ever do this in English' .... – cfr Sep 1 '17 at 12:39
  • 2
    @HenriMenke - Rather than insert a kern directly (between the "f" and the "l"), it would be better to insert a discretionary, with a kern in the discretionary's third argument. That way, the line-breaking algorithm could still operate on the word "leaflet". – Mico Sep 1 '17 at 22:33

A major, and frankly vexing, practical issue when breaking up typographically inappropriate fl and ffl ligatures is how much whitespace (if any) should be inserted between f (or ff) and l. This issue doesn't come up when breaking up ff ligatures (cf "shelfful" and the screenshot below), and it's generally a less-vexing issue when breaking up fi (e.g., "aufisst" in German) and ffi (e.g., "Stoffisolierung") ligatures.

The "right" amount of whitespace that should be inserted between f (or ff) and l happens to depend crucially on the exact shapes of the f and ff glyphs. For some fonts, such as Palatino, Aldus, and Dante, no extra whitespace is needed at all, as these fonts' f and ff glyphs have fairly short "arms" which don't collide with the l glyph even if no whitespace is inserted. (Aside: this is probably a deliberate design feature of these fonts.) The babel package's "| method is programmed to insert 0.03em of whitespace. While this amount is OK for Computer Modern and Latin Modern, it is actually way too much for Palatino on the one hand and not enough for fonts such as EB Garamond, Caslon, Sabon, and Linux Liberine O on the other. For EB Garamond, for instance, it looks like 0.1em -- or more than three times the amount inserted with babel's "| method -- is the amount of whitespace that must be inserted if the f and l glyphs absolutely, positively must not touch each other. In my opinion, the typeset word "Verzweiflung" looks just awful if 0.1em of whitespace is inserted: One problem -- the inappropriate fl ligature -- has been replaced with a problem -- the unsightly gap inside the word -- that's nearly as bad! (Another aside: Maybe the "typographic rule" you mention, that adjacent non-ligated glyphs must not touch, has to be reconsidered.)

The real solution when breaking up fl and ffl ligatures, then, is to use variants of the glyphs f and ff that have "short" arms, i.e., arms that don't protrude (much) to the right and hence don't collide with a "tall" glyph such as l. Unfortunately, very few fonts currently offer such short-armed glyphs. I'm aware of only EB Garamond and Linux Libertine as font families that provide them. (Tediously, the "slots" where EB Garamond and Linux Libertine store their short-armed f-variants aren't the same. This makes programming up an automated use of the short-armed glyphs rather tedious and error-prone. This is also why I haven't gotten around to implement the short-f approach in the selnolig package...)

Another solution, which may or may not be available to you, is to use a font such as Palatino whose f and ff glyphs have short arms and thus don't collide with trailing l glyphs.

The following table compares the outputs of various methods for breaking up fl ligatures. Note that the "new" method used below is similar to the one David Carlisle used in his answer, except that it uses a so-called "discretionary" to continue to allow line breaks (with hyphens) to occur in the word "Verzweiflung". Note also that no whitespace has to be inserted between the 2 f glyphs in shelfful, for any of the fonts considered here.

enter image description here


function breaklig (s)
    s = s:gsub ( 'Verzweiflung' ,
        'Ver\\-zweif\\discretionary{-}{}{\\kern0.10em}lung' )
    return s
luatexbase.add_to_callback( 'process_input_buffer' ,
    breaklig , 'break ligatures in specified words' )


&&    \multicolumn{2}{c}{\ttfamily selnolig}  &
      \multicolumn{1}{c}{\ttfamily babel "|}     &
      \multicolumn{1}{c}{\ttfamily "new"\ meth.} &
      \multicolumn{1}{c@{}}{\ttfamily f.short}\\
&&   \multicolumn{2}{c}{\ttfamily ("whatsit")} &
     \multicolumn{1}{c}{\ttfamily (0.03em)}  &
     \multicolumn{1}{c}{\ttfamily (0.10em)}  &
     \multicolumn{1}{c@{}}{(if available)} \\

\cmidrule(lr){3-4} \cmidrule(lr){5-5} \cmidrule(lr){6-6} \cmidrule(l){7-7}

% start with default font (Latin Modern)
\setmainfont{Latin Modern Roman}
Latin Modern
&ff fl & shelfful & {V}erzweiflung & Verzweif"|lung & Verzweiflung \\

\gdef\xx{\setmainfont{EB Garamond}[Scale=MatchLowercase]}
\xx EB Garamond
&ff fl & shelfful & {V}erzweiflung & Verzweif"|lung & Verzweiflung & 

\gdef\xx{\setmainfont{Adobe Caslon Pro}[Scale=MatchLowercase]}
\xx Caslon
&ff fl & shelfful & {V}erzweiflung & Verzweif"|lung & Verzweiflung \\

\gdef\xx{\setmainfont{Sabon Next LT Pro}[Scale=MatchLowercase]}
\xx Sabon
&ff fl & shelfful & {V}erzweiflung & Verzweif"|lung & Verzweiflung \\

\gdef\xx{\setmainfont{Palatino Linotype}[Scale=MatchLowercase]}
\xx Palatino
&ff fl & shelfful & {V}erzweiflung & Verzweif"|lung & Verzweiflung \\

\gdef\xx{\setmainfont{Linux Libertine O}[Scale=MatchLowercase]}
\xx Linux Lib.\ O
&ff fl & shelfful & {V}erzweiflung & Verzweif"|lung & Verzweiflung &

\setmainfont{EB Garamond}
Another comparison of the methods' outputs (EB Garmond only):

\uselig{höflich} & \uselig{trefflich} & \uselig{aufisst} & bad!\\
höflich & trefflich & aufisst & selnolig \\
höf"|lich & treff"|lich & auf"|isst & babel \verb+"|+ \\
& treff\discretionary{-}{}{\kern0.10em}lich 
& auf\discretionary{-}{}{\kern0.10em}isst
&  ``new'' method --- not good either \\
& tre\symbol{983904}\-lich 
& au\symbol{983911}\-isst
&  f.short \& f\_f.short --- best!
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.