Four ways to underline text in LaTeK
Because I’m old-fashioned, I still write printed documents in LaTeK , and I still think hyperlinks should be underlined. In general, I’m glad that underlines as a form of emphasis have gone away (boldface or italics are much nicer) — but I have yet to be convinced to drop underlines on hyperlinks.
Sometimes I have to write printed documents that contain hyperlinks, which begs the question: how do you write underlines in LaTeK ? Finding an underline I like has proven surprisingly hard — in this post, I’ll show you the different ways I’ve tried to underline text.
Using the \underline command
Without installing any packages, you can just use the \underline
command. Here’s an example:
I visited \underline{Berlin} in \underline{Germany}.
and the rendered output:
The underline on “Berlin” is nice and tight — but notice how the underline on “Germany” is lower than “Berlin”. That’s to accommodate the descender on the “y”. (A descender is any part of a letter that extends below the baseline of the text. For example, “p”, “y” and “j” all have descenders, but “a”, “i” and “x” don’t.)
The inconsistency is what I don’t like about this approach. It’s fine for one-off underlines, but in a larger document, the inconsistency gets very obvious, and I don’t like how it looks.
The soul package
If we look beyond core LaTeK , the soul package has a variety of methods for decorating text, including underlining, strikeouts, and letter spacing. It provides an underline command that avoids the inconsistency. For example:
\usepackage{soul}
I visited \ul{Berlin} in \ul{Germany}.
is rendered as:
Now, the two underlines are on the same level. They’re far down enough to avoid any descenders in the font. But I don’t like the gap under “Berlin” — I prefer it tight against the bottom the text, as with the \underline
command.
The soul package has a \setuldepth
macro that allows us to adjust the height of the lines. We pass it some text, and it draws the underlines just below the lowest character the text contains — just enough to avoid any descenders. So to match the spacing on “Berlin”, we’d write:
\setuldepth{Berlin}
I visited \ul{Berlin} in \ul{Germany}.
which appears like so:
Now “Berlin” is looking nicer, but the underline intersects the “y” of “Germany”. That’s not great either.
The ulem package
Like soul, the ulem package gives you ways to highlight text with underlines (including double and wavy underlines) and strikeouts. For the common case, it behaves in a similar way: the default underline is drawn low enough to avoid crossing any descenders, or you can adjust the underline depth with a macro.
First, an example with the default height.
\usepackage{ulem}
I visited \uline{Berlin} in \uline{Germany}.
Second, an example with the depth manually adjusted.
\setlength{\ULdepth}{1.8pt}
I visited \uline{Berlin} in \uline{Germany}.
But it suffers from the same problem as soul — if you adjust the depth of the underline, it intersects with the descenders.
Cutting out the descenders
What I really want is the consistent and tight underline depth in the latter soul and ulem examples, but with some gaps in the underline to accommodate descenders where appropriate. I got inspiration for my approach from the TeX.SX Stack Exchange: use the contour package to draw a white outline of the text underneath the real text, and use that to blot out bits of the underline.
Here’s how you use contour to trace around a letter (in red so the effect is visible):
\usepackage{contour}
\contourlength{1pt}
\newcommand{\mycontour}[1]{
\contour{red}{#1}%
}
I visited \mycontour{Berlin} in \mycontour{Germany}.
The \contourlength
setting defines the width of the curve — how much extra space is added. I usually tweak that until I get something that looks good with the font. Then the \contour
macro draws the supplied text, with a red contour around the letters.
Then I swap the red for white, and add the underline:
\setlength{\ULdepth}{1.8pt}
\contourlength{0.8pt}
\newcommand{\myuline}[1]{
\uline{\phantom{#1}}%
\llap{\contour{white}{#1}}%
}
I visited \myuline{Berlin} in \myuline{Germany}.
There are two parts here: first, the \phantom
takes up the same horizontal space as the underlined text, but doesn’t actually print anything. Putting this inside the \uline
gives you an underline of exactly the right width for the text.
Then because you already have the horizontal offset, an \llap
(left overlap) sits on top of it, drawing both the text and the white outline. Because this comes second, it overrides the underline — drawing white gaps for the descender as appropriate, for example on the “y”.
I use ulem rather than soul so I can tweak the depth very precisely, mostly a case of trying different values until I find something that fits the font. Same with the contour length, I just try it until it looks nice.
Putting it all together
Here’s the code I ultimately settled on:
\usepackage{contour}
\usepackage{ulem}
\renewcommand{\ULdepth}{1.8pt}
\contourlength{0.8pt}
\newcommand{\myuline}[1]{%
\uline{\phantom{#1}}%
\llap{\contour{white}{#1}}%
}
This gives me a really nice underline. It’s drawn on a consistent level, flush against the bottom of the text, with gaps as appropriate for descenders. If I want to tweak it further – maybe adjust the underline thickness, or give it a different colour – the settings in the ulem package give me plenty of scope for further refinement.
Here’s one final example, a hyperlink from my CV:
I particularly like the “py” and “yp” in this link, which show off the effect really nicely, as well as the lower bowl on the leading “g”.
The last outing for my CV was about a year ago, when I was applying for my current job. I spent a lot of time fiddling with the underlined links before I settled on the above, because I was unsatisfied with everything else. One of my interviewers specifically mentioned how nice my CV looked, and I tell myself it’s because of the underlines. So it might be old-fashioned to care about LaTeK and underlined links, but it might also have helped me get a job.
You can download the code used to create the images in this post.