# How to “highlight” text/formulas with tikz?

I try to construct a yellow rectangle (with tikz) so that I can use it to "highlight" a piece of text. Below you see a minimal example. It already looks good, but how can I avoid the word "dummy" to be raised? All words should be located at the same height.

\documentclass{scrartcl}

\usepackage[T1]{fontenc}
\usepackage[american,ngerman]{babel}
\usepackage{tikz}

\newcommand*{\yellowemph}[1]{%
\tikz\node[rectangle, fill=yellow, rounded corners, inner sep=0.3mm]{#1};%
}

\begin{document}
Just some \yellowemph{dummy} text to see what happens.
\end{document}


UPDATE

Thank you all for your help. Below, I included a short overview/comparison about the suggested approaches. Unfortunately, Versions 3 and 4 overwrite the text. Version 2 (soul) did not work within math mode (not even by wrapping it in \text{}). I like Version 1. See this page for how to automatically determine if in math mode or not: \newcommand: How to determine if in math mode (and then include )?

\documentclass{article}

\usepackage[T1]{fontenc}
\usepackage[american,ngerman]{babel}
\usepackage{tikz}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% version 1: needs  in math mode; not work across line boundaries
\newcommand*{\yellowemph}[1]{%
\tikz[baseline=(text.base)]\node(text)[rectangle, fill=yellow, rounded
corners, inner sep=0.3mm]{#1};%
}

% version 2: does not seem to work in math mode, not even with 
\usepackage{soul}% use \hl{} to highlight

% version 3: does not work across line boundaries
% see http://tex.stackexchange.com/questions/35319/a-boxed-alternative-with-minimal-spacing/35357#35357
\usetikzlibrary{calc, shapes}
\makeatletter
\newcommand*{\@DrawBoxHeightSep}{0.030em}%
\newcommand*{\@DrawBoxDepthSep}{0.025em}%
\newcommand{\@DrawBox}[3][red]{% #1=style, #2=height, #3=depth
\tikz[overlay,remember picture]{
\draw[#1]
($(bl)+(-0.2em,#2+\@DrawBoxHeightSep)$) rectangle
($(br)+(0.2em,-#3-+\@DrawBoxDepthSep)$);}
}
\newcommand{\tikzmark}[1]{\tikz[overlay,remember picture] \node (#1) {};}
\newdimen\@myBoxHeight%
\newdimen\@myBoxDepth%
\newcommand{\MyBox}[2][red]{%
\settoheight{\@myBoxHeight}{#2}% record height of box
\settodepth{\@myBoxDepth}{#2}% record height of box
\tikzmark{bl}#2\tikzmark{br}\@DrawBox[#1]{\@myBoxHeight}{\@myBoxDepth}% draw the box
}
\makeatother

% version 4: text gets overwritten
% see
% http://tex.stackexchange.com/questions/5959/cool-text-highlighting-in-latex
% \usepackage{soul}
% \usepackage{tikz}
% \usetikzlibrary{calc}
\usetikzlibrary{decorations.pathmorphing}

\makeatletter

\newcommand{\defhighlighter}[3][]{%
\tikzset{every highlighter/.style={color=#2, fill opacity=#3, #1}}%
}

\defhighlighter{yellow}{.5}

\newcommand{\highlight@DoHighlight}{
\fill [ decoration = {random steps, amplitude=1pt, segment length=15pt}
, outer sep = -15pt, inner sep = 0pt, decorate
, every highlighter, this highlighter ]
($(begin highlight)+(0,8pt)$) rectangle ($(end highlight)+(0,-3pt)$) ;
}

\newcommand{\highlight@BeginHighlight}{
\coordinate (begin highlight) at (0,0) ;
}

\newcommand{\highlight@EndHighlight}{
\coordinate (end highlight) at (0,0) ;
}

\newdimen\highlight@previous
\newdimen\highlight@current

\DeclareRobustCommand*\highlight[1][]{%
\tikzset{this highlighter/.style={#1}}%
\SOUL@setup
%
\def\SOUL@preamble{%
\begin{tikzpicture}[overlay, remember picture]
\highlight@BeginHighlight
\highlight@EndHighlight
\end{tikzpicture}%
}%
%
\def\SOUL@postamble{%
\begin{tikzpicture}[overlay, remember picture]
\highlight@EndHighlight
\highlight@DoHighlight
\end{tikzpicture}%
}%
%
\def\SOUL@everyhyphen{%
\discretionary{%
\SOUL@setkern\SOUL@hyphkern
\SOUL@sethyphenchar
\tikz[overlay, remember picture] \highlight@EndHighlight ;%
}{%
}{%
\SOUL@setkern\SOUL@charkern
}%
}%
%
\def\SOUL@everyexhyphen##1{%
\SOUL@setkern\SOUL@hyphkern
\hbox{##1}%
\discretionary{%
\tikz[overlay, remember picture] \highlight@EndHighlight ;%
}{%
}{%
\SOUL@setkern\SOUL@charkern
}%
}%
%
\def\SOUL@everysyllable{%
\begin{tikzpicture}[overlay, remember picture]
\path let \p0 = (begin highlight), \p1 = (0,0) in \pgfextra
\global\highlight@previous=\y0
\global\highlight@current =\y1
\endpgfextra (0,0) ;
\ifdim\highlight@current < \highlight@previous
\highlight@DoHighlight
\highlight@BeginHighlight
\fi
\end{tikzpicture}%
\the\SOUL@syllable
\tikz[overlay, remember picture] \highlight@EndHighlight ;%
}%
\SOUL@
}
\makeatother

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\begin{document}
\noindent
word $\frac{1}{2}$ $\displaystyle\frac{1}{2}$\\
\yellowemph{word} \yellowemph{$\frac{1}{2}$}
\yellowemph{$\displaystyle\frac{1}{2}$} $\yellowemph{$\displaystyle\frac{1}{2}$}$; Version 1: does not work across lines\\
\hl{word} \hl{$\frac{1}{2}$} \hl{$\displaystyle\frac{1}{2}$}
%$\text{\hl{$\displaystyle\frac{1}{2}$}}$
; Version 2: soul, does not work \emph{within} math mode!\\
\MyBox[fill=yellow, draw=yellow, opacity=0.3]{word} \MyBox[fill=yellow,
draw=yellow, opacity=0.3]{$\frac{1}{2}$} \MyBox[fill=yellow, draw=yellow,
opacity=0.3]{$\displaystyle\frac{1}{2}$}
%$\MyBox[fill=yellow, draw=yellow, opacity=0.3]{$\displaystyle\frac{1}{2}$}$
; Version 3: overwrites text; does not work \emph{within} math mode or across lines\\
\highlight{word} \highlight{$\frac{1}{2}$}
\highlight{$\displaystyle\frac{1}{2}$} $\highlight{$\displaystyle\frac{1}{2}$}$;
Version 4: overwrites text
\end{document}

-
Is A \boxed alternative with nicer spacing? what you are looking for? –  Peter Grill Mar 2 '12 at 0:56
–  Werner Mar 2 '12 at 0:58
Werner's comment may mean \tikz[baseline=(text.base)]\node (text) [rectangle, fill=yellow, rounded corners, inner sep=0.3mm]{#1}; for your case. –  Stefan Kottwitz Mar 2 '12 at 1:05
Thanks a lot for helping. I posted an update above. –  Marius Hofert Mar 2 '12 at 12:38

You can give the node a name and align to the baseline of that:

## Code:

\documentclass{scrartcl}

\usepackage[T1]{fontenc}
\usepackage[american,ngerman]{babel}
\usepackage{tikz}

\newcommand*{\yellowemph}[1]{%
\tikz[baseline=(X.base)] \node[rectangle, fill=yellow, rounded corners, inner sep=0.3mm] (X) {#1};%
}

\begin{document}
Just some \yellowemph{dummy} text to see what happens.
\end{document}

-
Maybe mdframed for paragraphs? –  percusse Mar 2 '12 at 1:34
@percusse: Thought about that, but that only does entire paragraphs, not portions of text within paragraphs which is sort of what is indicated by the MWE. You could perhaps add that as an alternate in case entire paragraphs need to be highlighted. –  Peter Grill Mar 2 '12 at 1:57
Ah, I should better not. You are much more fluent with those. I was really asking with ignorance :) –  percusse Mar 2 '12 at 1:59
Thanks for helping, aligning to the baseline is quite nice. –  Marius Hofert Mar 2 '12 at 12:37

Here's the code that I currently use for this. I use it mainly for highlighting (or fading) short segments of presentations, so it isn't designed to cope with long sections (though it makes a reasonable stab at it) and it almost certainly would go potty with page breaks. It's major drawback is that it doesn't automatically adjust to the size of the text because it doesn't work by putting the text in a box. Rather, it draws the highlighting under (for highlighting, over for fading) the text. So you should think of it more as getting a highlighter pen and highlighting text instead of drawing a box and filling it. Of course, you can use a thicker pen and there are keys to customise such stuff.

There are three variants: a highlighter, a fader, and a vertical highlighter. Each works by marking the start and end of the part you want marked. Then TikZ draws thick lines of the highlighter colour from the start to the end. If the displacement warrants it, the lines wrap (vertically in the case of the vertical highlighter). The difference between the highlighter and the fader is when the lines are drawn. For the highlighter, the lines emanate from the starting position, effectively placing them under the text. For the fader, the lines emanate from the ending position, placing them over the text.

Here's a sample:

Here's the code. I've tried to make it work with both beamer and non-beamer. In beamer, you get to do things like \highlight<2>{only on slide 2}. There are two ways to invoke the highlighting. One is to say \highlight{text to be highlighted} the other is to say \hlstart text to be highlighted \hlend. Sometimes the latter gives a bit more flexibility (the vertical highlighting in the above was done this way).

Here's the code. The amsmath package is just for the bmatrix environment. The above sample was actually produced using beamer (and uncommenting the frame environment).

\documentclass{article}
%\url{http://tex.stackexchange.com/q/46434/86}
\usepackage{amsmath}
\usepackage{tikz}

\makeatletter

%
% Highlighter code
%

\tikzset{%
remember picture with id/.style={%
remember picture,
overlay,
save picture id=#1,
},
save picture id/.code={%
\edef\pgf@temp{#1}%
\immediate\write\pgfutil@auxout{%
\noexpand\savepointas{\pgf@temp}{\pgfpictureid}}%
}
}

\def\savepointas#1#2{%
\expandafter\gdef\csname save@pt@#1\endcsname{#2}%
}

\tikzdeclarecoordinatesystem{pic}{%
\@ifundefined{save@pt@#1}{%
\pgfpointorigin
}{%
\pgfsys@getposition{\csname save@pt@#1\endcsname}\save@orig@pic%
\pgfsys@getposition{\pgfpictureid}\save@this@pic%
\pgf@process{\pgfpointorigin\save@this@pic}%
\pgf@xa=\pgf@x
\pgf@ya=\pgf@y
\pgf@process{\pgfpointorigin\save@orig@pic}%
}%
}

\newcounter{highlight}
\newcommand{\hlstart}{\tikz[remember picture with id=hlstart\the\value{highlight},baseline=-0.7ex];\hl@start}
\newcommand{\hlend}{\tikz[remember picture with id=hlend\the\value{highlight},baseline=-0.7ex];\hl@end\stepcounter{highlight}}
\newcommand{\fdstart}{\tikz[remember picture with id=hlstart\the\value{highlight},baseline=-0.7ex];\fd@start}
\newcommand{\fdend}{\tikz[remember picture with id=hlend\the\value{highlight},baseline=-0.7ex];\fd@end\stepcounter{highlight}}
\newcommand{\vlstart}{\tikz[remember picture with id=hlstart\the\value{highlight},baseline=-1em];\vl@start}
\newcommand{\vlend}{\tikz[remember picture with id=hlend\the\value{highlight},baseline=0.3ex];\vl@end\stepcounter{highlight}}

\newcommand{\hl@start}[1][]{%
\hl@draw{highlighter}{#1}{\the\value{highlight}}}

\newcommand{\hl@end}{}

\newcommand{\fd@start}[1][]{%
\def\fd@args{#1}}

\newcommand{\vl@start}[1][]{%
\vl@draw{highlighter}{#1}{\the\value{highlight}}}

\newcommand{\vl@end}{}

\def\hl@sets{%
\edef\hl@sx{\the\pgf@x}%
\edef\hl@sy{\the\pgf@y}%
}
\def\hl@sete{%
\edef\hl@ex{\the\pgf@x}%
\edef\hl@ey{\the\pgf@y}%
}

\def\page@node{
\path (current page.south east)
++(-\beamer@rightmargin,\footheight)
node[
minimum width=\textwidth,
minimum height=\textheight,
anchor=south east
] (page) {};
}

}{

\def\page@node{
\path (current page.north west)
++(\hoffset + 1in + \oddsidemargin + \leftskip,\voffset + 1in + \topmargin + \headheight + \headsep)
node[
minimum width=\textwidth - \leftskip - \rightskip,
minimum height=\textheight,
anchor=north west
] (page) {};
}

}

\newcommand{\hl@draw}[3]{%
\begin{tikzpicture}[remember picture,overlay]%
\page@node
\tikzset{#2,highlight=#1,every path/.append style={highlight=#1}}%
\pgfmathsetlengthmacro{\hl@width}{\the\pgflinewidth - 1pt}%
\coordinate (hlstart) at (pic cs:hlstart#3);
\coordinate (hlend) at (pic cs:hlend#3);
\tikz@scan@one@point\hl@sets(pic cs:hlstart#3)
\tikz@scan@one@point\hl@sete(pic cs:hlend#3)
\ifdim\hl@sy=\hl@ey\relax
\draw (hlstart) -- (hlend);
\else
\draw (hlstart) -- (hlstart -| page.east);
\pgfmathsetlengthmacro{\hl@sy}{\hl@sy -\hl@width}%
\pgfmathsetlengthmacro{\hl@ey}{\hl@ey +\hl@width}%
\loop\ifdim\hl@sy>\hl@ey\relax
\draw (0,\hl@sy -| page.west) -- (0,\hl@sy -| page.east);
\pgfmathsetlengthmacro{\hl@sy}{\hl@sy -\hl@width}%
\repeat
\draw (hlend -| page.west) -- (hlend);
\fi
\end{tikzpicture}%
}

\newcommand{\vl@draw}[3]{%
\begin{tikzpicture}[remember picture,overlay]%
\page@node
\tikzset{#2,highlight=#1,every path/.append style={highlight=#1}}%
\pgfmathsetlengthmacro{\hl@width}{\the\pgflinewidth - 1pt}%
\coordinate (hlstart) at (pic cs:hlstart#3);
\coordinate (hlend) at (pic cs:hlend#3);
\tikz@scan@one@point\hl@sets(pic cs:hlstart#3)
\tikz@scan@one@point\hl@sete(pic cs:hlend#3)
\ifdim\hl@sx=\hl@ex\relax
\draw (hlstart) -- (hlend);
\else
\draw (hlstart) -- (hlstart |- page.south);
\pgfmathsetlengthmacro{\hl@sx}{\hl@sx -\hl@width}%
\pgfmathsetlengthmacro{\hl@ex}{\hl@ex +\hl@width}%
\loop\ifdim\hl@sx>\hl@ex\relax
\draw (\hl@sx,0 |- page.north) -- (\hl@sx,0 |- page.south);
\pgfmathsetlengthmacro{\hl@sx}{\hl@sx -\hl@width}%
\repeat
\draw (hlend |- page.north) -- (hlend);
\fi
\end{tikzpicture}%
}

\tikzset{%
highlight/.default=highlighter,
highlight/.style={
color=\pgfkeysvalueof{/tikz/#1 colour},
line width=\pgfkeysvalueof{/tikz/#1 width},
line cap=\pgfkeysvalueof{/tikz/#1 cap},
opacity=\pgfkeysvalueof{/tikz/#1 opacity},
},
highlighter colour/.initial=yellow,
highlighter width/.initial=12pt,
highlighter cap/.initial=butt,
highlighter opacity/.initial=1,
}

%% Beamer variants

\setbeamercolor{highlighted text}{bg=yellow}

\newcommand<>{\highlight}[2][]{%
\only#3{\hlstart[#1]}#2\only#3{\hlend}}

\only#3{\fdstart[#1]}#2\only#3{\fdend}}

\newcommand<>{\vhighlight}[2][]{%
\only#3{\vlstart[#1]}#2\only#3{\vlend}}

}{

\newcommand{\highlight}[2][]{%
\hlstart[#1]#2\hlend}

\fdstart[#1]#2\fdend}

\newcommand{\vhighlight}[2][]{%
\vlstart[#1]#2\vlend}

}

\makeatother

\begin{document}
%\begin{frame}

This is some \highlight{highlighted} text.  With displaystyle maths, we might have to adjust the line width to get \highlight[highlighter width=24pt]{$$\displaystyle \frac12$$}.

\highlight[highlighter cap=round]{For a very long line, we get basic line wrapping.  It's a little creaky around the edges so may not be as robust as it could be.}

Vertical highlighting is useful in matrices:
%
$\begin{bmatrix} 1 & \vlstart 2 & 3 \\ 4 & \vlend 5 & 6 \end{bmatrix}$

%\end{frame}
\end{document}

-
Amazing what TikZ can do. Nice! –  azetina Mar 2 '12 at 16:37
@azetina *starts singing* "Because, because, because, because ... because of the wonderful things TikZ does." –  Loop Space Mar 2 '12 at 16:47
:-) La la lalalala lala –  azetina Mar 2 '12 at 16:55
Andrew, that is an impressive example for advanced TikZing. I especially do like the route over the own coordinate system! A bit more commenting of the source (what every component is for) would be nice, though :-) –  Daniel Mar 2 '12 at 22:57
@Daniel In my defence, it is code that I wrote for myself and almost just cut-and-pasted here! –  Loop Space Mar 2 '12 at 23:31

Like Peter's answer but without adding a new name for the node

\documentclass{scrartcl}
\usepackage[T1]{fontenc}
\usepackage[american,ngerman]{babel}
\usepackage{tikz}

\newcommand*{\yellowemph}[1]{%
\tikz[baseline]\node[rectangle, fill=yellow, rounded corners, inner sep=0.3mm,anchor=base]{#1};%
}
\begin{document}
Just some \yellowemph{dummy} text to see what happens.
\end{document}


-