21

I want to put some small boxes around certain words in a paragraph. The boxes will never contain more than one word.

The \ovalbox command described in the fancybox documentation is close to what I need. However, I found some problems:

  • The rounded corners do not line up with the sides perfectly.
  • Text to the left and right in the paragraph are pushed away.
  • The spacing between lines in the paragraph is increased vertically.

I would like to create boxes which:

  • Adjust horizontally to fit the width of the text inside.
  • Have rounded or beveled corners.
  • Can be filled with a solid color.
  • Will not cause any text inside or around the box to move.
  • Will not impact the vertical spacing of lines.
28

You can use TikZ with the overlay option and a correct anchor. That would look like this:

\documentclass{article}
\usepackage{tikz}
\newcommand\mybox[2][]{\tikz[overlay]\node[fill=blue!20,inner sep=2pt, anchor=text, rectangle, rounded corners=1mm,#1] {#2};\phantom{#2}}
\begin{document}
   \noindent
   this is some text \mybox[fill=blue!20]{box} text\\
   this is some text box text
\end{document}

You can specify extra options (like I have done here for the color). By using the overlay option and the text anchor we ensure correct placement and no influence on spacing. The phantom is added to get the normal spacing for the content of the box. This is the result of the example code:

TikZ text box

Edit: To show that the vertical spacing is not affected either, consider the following:

\documentclass{article}
\usepackage{tikz}
\newcommand\mybox[2][]{\tikz[overlay]\node[fill=blue!20,inner sep=2pt, anchor=text, rectangle, rounded corners=1mm,#1] {#2};\phantom{#2}}
\begin{document}
  \begin{minipage}{0.4\textwidth}
    \noindent
    this is some text \mybox[fill=blue!20]{box} text\\
    this is some text box text
  \end{minipage}
  \begin{minipage}{0.4\textwidth}
    \noindent
    this is some text box text\\
    this is some text box text
  \end{minipage}    
\end{document}

Which results in:

TikZ text box vertical spacing

  • 2
    \def\mybox[#1]#2 would force the "optional" argument, so \newcommand\mybox[2][] would be better. – Martin Scharrer Nov 28 '11 at 14:27
  • @MartinScharrer: You are absolutely correct. I have modified the answer to reflect this. The [fill=blue!20] is now of course also optional on the \mybox command. – Roelof Spijker Nov 28 '11 at 14:33
  • 1
    @Herbert: With vertical spacing I was referring to the vertical space between lines as the OP mentions. The vertical size of the box is indeed dependent on what is inside. If this is unwanted you could add text depth=0pt as an option to the node. This does not fix it entirely though. There are multiple options, the easiest is to set text height=1.5ex. This way you will have uniform box height. – Roelof Spijker Nov 28 '11 at 16:07
  • 1
    Like it says in the answer: "The phantom is added to get the normal spacing for the content of the box". Basically, because the node is placed in 'overlay mode', it has 0 size when being placed. But we don't want the next word to overlap, so we add a phantom to take up the space that the word would normally take up without actually printing the word. Try removing the phantom and see what happens. (It's been a while since I used any of this, just saw your comment. So I'm really hoping this is actually true... Pretty sure it is :)) – Roelof Spijker Dec 1 '15 at 9:41
  • 1
    @MedVall, the #1 takes the value of the optional arguments. In the example I use fill=blue!20, which is superfluous because I already set it in the node command. Anyway, this value for #1 is added in the optional part of the node command. So you can give it a set of comma-separated arguments that the node command understands. – Roelof Spijker Feb 10 '16 at 12:50
11

My solution needs no special macros. No TikZ, no PSTricks. Only \pdfliteral primitive is used. And you can define \def\pdfliteral#1{\special{pdf:literal #1}} if \pdfliteral isn't available (for example in XeTeX).

\def\mybox#1{\leavevmode \setbox0=\hbox{#1}%
   \dimen0=\wd0 \edef\posxA{\expandafter\ignorept\the\dimen0 \space}%
   \hbox{\kern3pt\pdfliteral{q .8 .8 1 rg .8 .8 1 RG .9963 0 0 .9963 0 0 cm 1 j 1 J 6 w
                             0 0 m 0 5 l \posxA 5 l \posxA 0 l 0 0 l B Q}%
         \box0 \kern3pt}%
}
{\lccode`\?=`\p \lccode`\!=`\t  \lowercase{\gdef\ignorept#1?!{#1}}}

This is a \mybox{test} of my \mybox{box}.

\bye

roundbox

10

This kind of boxes can be done with extrude option from tcolorbox. A little example adapted from tcolorbox documentation:

\documentclass{article}
\usepackage[most]{tcolorbox}

\newtcbox{\mybox}[1][]{enhanced, colframe=blue, colback=blue!15, 
       frame style={opacity=0.25}, interior style={opacity=0.25}, 
       nobeforeafter, tcbox raise base, shrink tight, extrude by=1mm, #1}

\begin{document}
Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
Ut \mybox[extrude bottom by=2cm]{purus} elit, vestibulum ut, \mybox{placerat} ac, 
\mybox[extrude top by=2mm]{adipiscing} vitae, \mybox[extrude left by=5mm, extrude 
bottom by=2mm]{felis}. Curabitur dictum gravida mauris. \mybox{Nam} arcu libero,    
nonummy eget, consectetuer id, vulputate a, magna.
\end{document}

enter image description here

4

Basically similar to the solution given by Roelof Spijker. I suggest handling the optional argument differently, and use a \strut to ensure consistent box size while not changing the line spacing:

\documentclass{article}

\usepackage{tikz}

\newcommand\mmybox[2][fill=blue!20]{%
    \tikz[baseline]\node[%
        inner ysep=0pt, 
        inner xsep=2pt, 
        anchor=text, 
        rectangle, 
        rounded corners=1mm,
        #1] {\strut#2};%
}

\begin{document}
   \noindent
   this is some text \mmybox{Box} text\\
   this is some text box text
\end{document}

The results:

Sample of boxed text

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.