[Tex/LaTex] Multi-line box around a sentence in a paragraph

boxesframedtikz-pgf

I am trying to draw a polygon box around a sentence within a paragraph. This box would wrap over multiple lines and terminate exactly at the end of the sentence (i.e. without white space filling the remaining line width). Therefore, the box I'm trying to draw is not a simple rectangle like what is produced by \fbox. I've tried several different approaches:

  1. Using \fbox and \parbox to create a multi-line outline:

    \fbox{\parbox{\linewidth}{%
      Nunc sed pede. Praesent vitae lectus. Praesent neque justo, 
      vehicula eget, interdum id, facilisis et, nibh.}}
    
  2. Using TikZ:

    \newcommand\mybox[2][]{%
      \tikz[overlay]\node[fill=blue!20,inner sep=2pt, 
        anchor=text, rectangle, rounded corners=1mm,#1] {#2};\phantom{#2}}
    

Any help is greatly appreciated.


Here is a simple document that illustrates the above code:

\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}

\fbox{\parbox{\linewidth}{Nunc sed pede. Praesent vitae lectus. Praesent 
  neque justo, vehicula eget, interdum id, facilisis et, nibh.}} Phasellus 
  at purus et libero lacinia dictum. Fuscealiquet. Nulla eu ante placerat 
  leo semper dictum. Mauris metus. Curabitur lobortis. Curabitur 
  sollicitudin hendrerit nunc. Donec ultrices lacus id ipsum.

\mybox{Class aptent taciti sociosqu ad litora torquent per conubia nostra, 
  per incepto hymenaeos.} Aenean nonummy turpis id odio. Integer euismod 
  imperdiet turpis. Ut nec leo nec diam imperdiet lacinia. Etiam eget lacus 
  eget mi ultricies posuere. In placerat tristique tortor. Sed porta 
  vestibulum metus. Nulla iaculis sollicitudin pede. Fusce luctus tellus 
  in dolor. Curabitur auctor velit a sem. Morbi sapien. Class aptent taciti 
  sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos. 
  Donec adipiscing urna vehicula nunc. Sed ornareleo in leo. In rhoncus leo 
  ut dui. Aenean dolor quam, volutpat nec, fringilla id, consectetuer vel, pede

\end{document}

Best Answer

Update.

Improved version:

\tikzmark is used to set marks at the beginning and end of the text that will be boxed. The main command is

\BoxedText[<options>]{<start-mark>}{<end-mark>} 

The optional argument can be used to pass options to the \draw command used internally (by default, just a frame is drawn, but you can fill it, or change the line width, or apply any other desired valid modification):

\documentclass{article}
\usepackage{tikzpagenodes}
\usetikzlibrary{calc}

\makeatletter
\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}}%
  },
  if picture id/.code args={#1#2#3}{%
    \@ifundefined{save@pt@#1}{%
      \pgfkeysalso{#3}%
    }{
      \pgfkeysalso{#2}%
    }
  }
}

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

\def\tmk@labeldef#1,#2\@nil{%
  \def\tmk@label{#1}%
  \def\tmk@def{#2}%
}

\tikzdeclarecoordinatesystem{pic}{%
  \pgfutil@in@,{#1}%
  \ifpgfutil@in@%
    \tmk@labeldef#1\@nil
  \else
    \tmk@labeldef#1,(0pt,0pt)\@nil
  \fi
  \@ifundefined{save@pt@\tmk@label}{%
    \tikz@scan@one@point\pgfutil@firstofone\tmk@def
  }{%
  \pgfsys@getposition{\csname save@pt@\tmk@label\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}%
  \advance\pgf@x by -\pgf@xa
  \advance\pgf@y by -\pgf@ya
  }%
}
\newcommand\tikzmark[2][]{%
\tikz[remember picture with id=#2] #1;}
\makeatother

\newcommand\BoxedText[3][]{%
\begin{tikzpicture}[remember picture,overlay]
\draw[#1] 
  let \p1=(pic cs:#2), \p2=(pic cs:#3) in
  ([yshift=-0.8ex]\p1) --
  ([yshift=2ex]\p1) -- 
  ([xshift=3pt,yshift=2ex]\p1-|current page text area.east) -- 
  ([xshift=3pt,yshift=2ex]\p2-|current page text area.east) --
  ([yshift=2ex]\p2) --
  ([yshift=-0.8ex]\p2) --
  ([xshift=-3pt,yshift=-0.8ex]\p2-|current page text area.west) --
  ([xshift=-3pt,yshift=-0.8ex]\p1-|current page text area.west) --
  cycle
;
\end{tikzpicture}%
}

\begin{document}

\BoxedText{start1}{end1}
\BoxedText[draw=orange!70!black,right color=orange!10,left color=orange!50]{start2}{end2}
\BoxedText[draw=cyan!70!black,fill=cyan!30,ultra thick]{start3}{end3}

Some text goes here.\tikzmark{start1} Some text goes here. Some text goes here. Some text goes here. Some text goes here. Some text goes here. Some text goes here. Some text goes here. Some text goes here. Some text goes here. Some text goes here.\tikzmark{end1} Some text goes here. Some text goes here. Some text goes here. Some text goes here. Some text goes here. Some text goes here.

Some text goes here. Some text goes here. Some text goes here. Some text goes here.Some text goes here.\tikzmark{start3} Some text goes here. Some text goes here. Some text goes here. Some text goes here. Some text Some text goes here.\tikzmark{end3}

Some text goes here. Some text goes here. Some text goes here. Some text goes here. Some text goes here.Some text goes here. Some text goes here. Some text goes here. Some text goes here.Some text goes here.\tikzmark{start2} Some text goes here. Some text goes here. Some text goes here. Some text goes here. Some text goes here. Some text goes here. Some text goes here. Some text goes here. Some text goes here. Some text goes here. Some text goes here. Some text goes here. Some text goes here. Some text goes here. Some text goes here. Some text goes here.\tikzmark{end2} Some text goes here. Some text goes here. Some text goes here. Some text goes here. Some text goes here. Some text goes here. Some text goes here.

\end{document}

enter image description here

The code must be run three times.