# underline omitting the descenders

I'm very well aware that it is considered best practice not to use underlining other than on typewriters and in handwriting. But sometimes it is needed nonetheless.

In my opinion the typographically least offending way to underline in print is to leave out the descenders. This is also how I learned to do it in handwriting. Very few fonts offer a pre-made underlined variant, but some text-processors (e.g. OS X text-engine) do -- depending on the font used -- an acceptable job at emulating this effect:

How would I tweak any of the existing ways/packages for underlining to do the same?

As a bonus, I'd like to be able to tweak the behaviour (extent of the omitted part, apply to which letters) per font and text style, preferably working with XeLaTeX.

We could do for each letter:

• Produce the underlining
• Overwrite the line with the same but bolder letter or with a left and right shifted one, but in background or white color
• Write the letter

So we would get an underline with matching gaps.

Here I modified the soul approach of Marco in this way, just for a demonstration what I mean, which could be improved (boldness, loop):

\setcounter{errorcontextlines}{999}
\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage[latin1]{inputenc}
\usepackage{soul}
\usepackage{color}
\makeatletter
\newcommand*{\whiten}[1]{\llap{\textcolor{white}{{\the\SOUL@token}}\hspace{#1pt}}}
\DeclareRobustCommand*\myul{%
\def\SOUL@everyspace{\underline{\space}\kern\z@}%
\def\SOUL@everytoken{%
\setbox0=\hbox{\the\SOUL@token}%
\ifdim\dp0>\z@
\raisebox{\dp0}{\underline{\phantom{\the\SOUL@token}}}%
\whiten{1}\whiten{0}%
\whiten{-1}\whiten{-2}%
\llap{\the\SOUL@token}%
\else
\underline{\the\SOUL@token}%
\fi}%
\SOUL@}
\makeatother
\begin{document}
\sffamily\Huge
\myul{jumping quickly}
\end{document}


• I really like your approach, but there's still a problem when the character's stem is even more narrow than the gap between descender and underline. Cf when removing \sffamily from your example. Any ideas how to solve this? Dec 3, 2011 at 10:44
• @Florian You could add \whiten{0}\whiten{-0.5} to get more removed. Or whiten in small steps in a loop. I'll add this when I've got time for it. Dec 3, 2011 at 11:05
• @StefanKottwitz I'd love to be able to do this with a thicker line. I tried simply using \ul (rather than underline) from soul and changing the thickness but that doesn't seem to work. Is that because I'm using it within the scope of a redefinition of the soul macros? Would it require a complete re-write of this to provide user set underline thickness? Jun 12, 2012 at 0:33
• I think this would make a fine package or addition to soul, perhaps adding some easy ways to tune the behaviour for the font used... Jun 26, 2012 at 12:09
• The \raisebox makes the line higher than necessary. It can be fixed by either the optional argument of \raisebox: \raisebox{\dp0}[\height]{\underline{\phantom{\the\SOUL@token}}}. Or it can be done in a simpler way without \raisebox: \underline{\kern\wd0}. Jun 4, 2014 at 1:26

Here is a solution using contour and ulem packages.

IMO this produces a very good looking underline, specialy for title underlining:

\documentclass{article}

\usepackage[outline]{contour}

\usepackage{ulem}
\normalem % use classical emph

\newcommand \myul[4]{%
\begingroup%
\renewcommand \ULdepth {#1}%
\renewcommand \ULthickness {#2}%
\contourlength{#3}%
\uline{\phantom{#4}}\llap{\contour{white}{#4}}%
\endgroup%
}

\newcommand \myulline[4]{%
\begingroup%
\renewcommand \ULdepth {#1}%
\renewcommand \ULthickness {#2}%
\contourlength{#3}%
\noindent\rlap{\uline{\hspace{\textwidth}}}\contour{white}{#4}%
\endgroup%
}

\begin{document}
\bfseries

\Huge
\myulline{5pt}{1pt}{2pt}{Chapter Eight}

\vspace{1cm}

\normalsize
\normalfont

Test. \myul{2pt}{0.5pt}{1pt}{Quit jumping quickly!} Test.

Test. \myul{1.2pt}{0.5pt}{0.5pt}{Quit jumping quickly!} Test.

\end{document}


Output:

Close up:

As drawback, the underline depth cannot be very close to baseline because it can be hidden by the contour.

• Done. I was waiting for a minimum of 10 points of reputation to be able to post images, this was my first contribution :) Oct 5, 2012 at 13:35
• Quite a nice first contribution! Hoping to see more of this :). This is a really nice underlining for titles -- as you said -- especially with the line extending to the right like in your example. For regular paragraph text, however, I'd indeed like the underline to be closer to the baseline. Oct 6, 2012 at 4:52
• This looks great but unfortunately seems to disable line breaks. Do you see any easy way to fix this? Jan 26, 2018 at 8:47
• This solution makes each word be found several times when searching in the pdf. Why and how to solve it? Jun 11, 2019 at 11:20

Simply because I found it useful here is a modification of Stefans answer above that lets you control the depth, thickness and width of the underline. This might be useful, for example, with a larger or bolder font. The syntax is: \varul<width>[depth][thickness]{stuff} where:

• <width> is optional and given as a multiple of 1/100 em, e.g. <10> would give a gap width of 0.1em. The default value is 5
• [depth] is optional and is given as a positive value (including units) that specifies the distance below the baseline to draw the underline. The default value is 0.2ex.
• [thickness] is optional and is given as a positive value (including units) specifying the thickness of the underline. The default value is 0.1ex
• The fourth, mandatory, argument is what you want underlined.

This will work across paragraphs and linebreaks but may change the spacing very slightly.

\documentclass{article}
\usepackage{soul}
\usepackage{xcolor}
\usepackage{xparse}
\makeatletter

\ExplSyntaxOn
\cs_new:Npn \white_text:n #1
{
\fp_set:Nn \l_tmpa_fp {#1 * .01}
\llap{\textcolor{white}{\the\SOUL@syllable}\hspace{\fp_to_decimal:N \l_tmpa_fp em}}
\llap{\textcolor{white}{\the\SOUL@syllable}\hspace{-\fp_to_decimal:N \l_tmpa_fp em}}
}
\NewDocumentCommand{\whiten}{ m }
{
\int_step_function:nnnN {1}{1}{#1} \white_text:n
}
\ExplSyntaxOff

\NewDocumentCommand{ \varul }{ D<>{5} O{0.2ex} O{0.1ex} +m } {%
\begingroup
\setul{#2}{#3}%
\def\SOUL@uleverysyllable{%
\setbox0=\hbox{\the\SOUL@syllable}%
\ifdim\dp0>\z@
\SOUL@ulunderline{\phantom{\the\SOUL@syllable}}%
\whiten{#1}%
\llap{%
\the\SOUL@syllable
\SOUL@setkern\SOUL@charkern
}%
\else
\SOUL@ulunderline{%
\the\SOUL@syllable
\SOUL@setkern\SOUL@charkern
}%
\fi}%
\ul{#4}%
\endgroup
}

\makeatother
\begin{document}

\varul{\Huge jumping quickly}\par\smallskip
\varul[1pt][1pt]{\Huge jumping quickly}

\end{document}


Edit by Tobi: \fp_mul:Nn doesn’t work in a current TeXlive, so I replaced the two lines with just \fp_set:Nn \l_tmpa_fp {#1 * .01}.

• Does this require TeX 2012, as I am getting an Undefined control sequence with TeXLive2011? Aug 14, 2012 at 0:11
• @PeterGrill Hi Peter I'm not familiar with TeXLive, nor with how it works. Likely, you're getting an undefined control sequence on \int_step_function:nnnN which was a recent addition (~June) to expl3. If you are able to update to the most recent version of expl3, then that should take care of the problem (assuming that I'm right about the control sequence). Aug 14, 2012 at 5:37
• Very nice solution! Perhaps you would consider packaging it and put it on CTAN? Aug 16, 2012 at 9:37
• This is a nice solution, but the text in the pdf is duplicated and thus not well-copyable Jun 7, 2019 at 12:46
• @Andrestand The why is because it prints multiple copies of the text on top of one another at different font sizes. Because of that, I can't see a solution to your issue using this method. Jun 12, 2019 at 16:59

here a solution which works also with pdflatex and using the advantages of the package soul:

\setcounter{errorcontextlines}{999}
\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage[latin1]{inputenc}
\usepackage{soul}
\makeatletter
\DeclareRobustCommand*\myul{%
\def\SOUL@everyspace{\underline{\space}\kern\z@}
\def\SOUL@everytoken{%
\setbox0=\hbox{\the\SOUL@token}%
\ifdim\dp0>\z@
\the\SOUL@token
\else
\underline{\the\SOUL@token}%
\fi}
\SOUL@}
\makeatother
\begin{document}
\myul{jumping quickly}

\end{document}


• Is there any way to fine-tune this code some more to take into account that the descenders of p and q take up less (horizontal) space below the line than do g, j, and y?
– Mico
Dec 2, 2011 at 15:02
• @Mico -- remember that tex doesn't know anything about the shape of the letters, only the dimensions of the defined bounding box. so an automatic adjustment is currently out of the question. but too bad -- it would be a really nice feature. Dec 2, 2011 at 17:47
• @barbarabeeton: Thanks, Barbara, for this refresher. (I had indeed temporarily forgotten this basic fact!) I guess the subject of how to provide more information than just the dimensions of a character's bounding box might be tackled one day by lua(la)tex programmers. :-)
– Mico
Dec 2, 2011 at 18:21
• @Mico: I think it is possible by using a virtual font but I don't know how ;-) Dec 2, 2011 at 19:46
• This method also prevents line continuation but the text in the pdf is correctly copyable Jun 7, 2019 at 12:44

I'm using the following adaption of CDSousa's answer, for two reasons: firstly, XCharter + contour for some reason looks more coarse than the other text; secondly, to allow for close underlining (the drawback pointed out by CDSousa):

\usepackage{ulem}
\normalem % use classical emph
\usepackage{color}
\usepackage{pgffor}
\newcommand\myul[4]{% arg 1: underline depth; arg 2: underline thickness; arg 3: space around descenders in pt (!)
\begingroup%
\renewcommand\ULdepth{#1}%
\renewcommand\ULthickness{#2}%
\uline{\phantom{\smash{#4}}}%
\foreach \hshift in {0.0, 0.1, ..., #3}{%
\foreach \upshift in {-0.4, -0.3, ..., 1.0}{%
\llap{\color{white}\raisebox{\upshift0pt}[0pt]{#4}\hspace{\hshift0pt}}%
\llap{\color{white}\raisebox{\upshift0pt}[0pt]{#4}\hspace{-\hshift0pt}}%
}%
}%
\llap{#4}%
\endgroup%


Example: \myul{1.75pt}{.5pt}{2}{Blupp of (that's \emph{of}, not \emph{off}, of course) a great Synopsis} has underline depth 1.75pt, underline thickness .5pt, and spacing 2pt, and looks like