create a framed environment for a margin note
Here's one possibility using the mdframed
package and \marginnote
from the marginnote
package:
\documentclass{article}
\usepackage[lmargin=5cm,textwidth=15cm,marginparwidth=4cm]{geometry}
\usepackage[dvipsnames]{xcolor}
\usepackage{ragged2e}
\usepackage[framemethod=tikz]{mdframed}
\usepackage{marginnote}
\usetikzlibrary{calc}
\usepackage{lipsum}
\reversemarginpar
\newsavebox\mybox
\newlength\BoxHt
\newcommand\caution[2][-2.2\baselineskip]{%
\begin{lrbox}{\mybox}
\parbox{\marginparwidth}{#2}
\end{lrbox}%
\settoheight\BoxHt{\usebox\mybox}%
\raisebox{\BoxHt}[0pt][0pt]{\marginnote{%
\begin{mdframed}[
userdefinedwidth=\marginparwidth,
innerleftmargin=3pt,
innerrightmargin=3pt,
linecolor=BrickRed,
frametitle=\colorbox{white}{\space Caution\space},
frametitlefont=\color{BrickRed}\sffamily,
innertopmargin=10pt,
frametitleaboveskip=-\ht\strutbox,
frametitlebelowskip=-\ht\strutbox,
frametitlealignment=\raggedright,
singleextra={\fill[BrickRed] let \p1=(P), \p2=(O) in
( $ (P|-0,0.5*\y2+0.5*\y1) + (0,-4pt) $ ) -- +(4pt,4pt) -- +(0,8pt) -- cycle;}
]\RaggedRight\small#2\end{mdframed}}[#1]}}
\begin{document}
\lipsum*[3-4]\caution{\lipsum[2]}\lipsum[3-5]
Some test text\caution{Some text goes here just to illustrate the command}
\end{document}
A zoomed image:
The optional argument for \caution
allows you to control the vertical shifting if necessary.
And here's another simpler option (which I personally like more) using tikz
(and tikzpagenodes
):
\documentclass{article}
\usepackage[lmargin=5cm,textwidth=15cm,marginparwidth=4cm]{geometry}
\usepackage[dvipsnames]{xcolor}
\usepackage{ragged2e}
\usepackage[framemethod=tikz]{mdframed}
\usepackage{tikzpagenodes}
\usetikzlibrary{calc}
\usepackage{lipsum}
\newcounter{mycaution}
\newcommand\tikzmark[1]{%
\tikz[remember picture,overlay]\node[inner xsep=0pt,outer sep=0pt] (#1) {};}
\newcommand\caution[1]{%
\stepcounter{mycaution}%
\tikzmark{\themycaution}%
\begin{tikzpicture}[remember picture,overlay]
\node[draw=BrickRed,anchor=east,xshift=-\marginparsep]
(mybox\themycaution)
at ([yshift=3pt]current page text area.west|-\themycaution)
{\parbox{\marginparwidth}{\vskip10pt\RaggedRight\small#1}};
\node[fill=white,font=\color{BrickRed}\sffamily,anchor=west,xshift=7pt]
at (mybox\themycaution.north west) {\ Caution!\ };
\fill[BrickRed]
([yshift=3pt]mybox\themycaution.east) --
([xshift=3pt]mybox\themycaution.east) --
([yshift=-3pt]mybox\themycaution.east) -- cycle;
\end{tikzpicture}%
}
\begin{document}
\lipsum*[3-4]\caution{\lipsum[2]}\lipsum[3-5]
Some test text\caution{Some text goes here just to illustrate the command}
\end{document}
And a zoomed image:
An improved version; now there's an optional argument allowing you to change the position of the box and of the pointer; possible values are b
, t
, and c
, to place the pointer at the bottom, at the top, and at the center, respectively, of the box:
\documentclass{article}
\usepackage[lmargin=5cm,textwidth=15cm,marginparwidth=4cm]{geometry}
\usepackage[dvipsnames]{xcolor}
\usepackage{ragged2e}
\usepackage[framemethod=tikz]{mdframed}
\usepackage{tikzpagenodes}
\usetikzlibrary{calc}
\usepackage{lipsum}
\newcounter{mycaution}
\newcommand\pointeranchor{}
\newcommand\boxanchor{}
\newlength\boxvshift
\newlength\uppertrianglecorner
\newcommand\tikzmark[1]{%
\tikz[remember picture,overlay]\node[inner xsep=0pt,outer sep=0pt] (#1) {};}
\newcommand\caution[2][c]{%
\stepcounter{mycaution}%
\tikzmark{\themycaution}%
\if#1b\relax
\renewcommand\pointeranchor{mybox\themycaution.south east}%
\renewcommand\boxanchor{south east}%
\setlength\boxvshift{-10pt}%
\setlength\uppertrianglecorner{13pt}%
\else
\if#1t\relax
\renewcommand\pointeranchor{mybox\themycaution.north east}%
\renewcommand\boxanchor{north east}%
\setlength\boxvshift{10pt}%
\setlength\uppertrianglecorner{-7pt}%
\else
\if#1c\relax
\renewcommand\pointeranchor{mybox\themycaution.east}%
\renewcommand\boxanchor{east}%
\setlength\boxvshift{0pt}%
\setlength\uppertrianglecorner{3pt}%
\fi\fi\fi%
\begin{tikzpicture}[remember picture,overlay]
\node[draw=BrickRed,anchor=\boxanchor,xshift=-\marginparsep,yshift=\boxvshift]
(mybox\themycaution)
at ([yshift=3pt]current page text area.west|-\themycaution)
{\parbox{\marginparwidth}{\vskip10pt\RaggedRight\small#2}};
\node[fill=white,font=\color{BrickRed}\sffamily,anchor=west,xshift=7pt]
at (mybox\themycaution.north west) {\ Caution!\ };
\fill[BrickRed]
([yshift=\uppertrianglecorner]\pointeranchor) --
([yshift=\uppertrianglecorner-3pt,xshift=3pt]\pointeranchor) --
([yshift=\uppertrianglecorner-6pt]\pointeranchor) -- cycle;
\end{tikzpicture}%
}
\newcommand\Test{Nulla malesuada porttitor diam. Donec felis erat, congue non, volutpat at, tincidunt tristique, libero. Vivamus viverra fermentum felis. Donec nonummy pellentesque ante. Phasellus adipiscing
semper elit.}
\begin{document}
\lipsum*[4]\caution[t]{\Test}\lipsum[3]\par\bigskip
\lipsum*[4]\caution{\Test}\lipsum[3]\par\bigskip
\lipsum*[4]\caution[b]{\Test}\lipsum[3]
\end{document}
The t
option is useful if the box will appear in the first lines of the text area; b
can be used in case the box will appear near the bottom of the text area.
A little variation required in a comment; now \caution has three optional arguments and a mandatory one:
\caution[<pos>][<color>][<title>]{<text>}
where ias an in the code immediately before, and can be b
, t
, or c
(default=c
); <color>
controls the color used for the frame and title (default=BrickRed
); <title>
changes the title used for the frame (defualt=Caption!
); <text>
is the content of the note.
\documentclass{article}
\usepackage[lmargin=5cm,textwidth=15cm,marginparwidth=4cm]{geometry}
\usepackage[dvipsnames]{xcolor}
\usepackage{ragged2e}
\usepackage{xparse}
\usepackage[framemethod=tikz]{mdframed}
\usepackage{tikzpagenodes}
\usetikzlibrary{calc}
\usepackage{lipsum}
\newcounter{mycaution}
\newcommand\pointeranchor{}
\newcommand\boxanchor{}
\newlength\boxvshift
\newlength\uppertrianglecorner
\newcommand\tikzmark[1]{%
\tikz[remember picture,overlay]\node[inner xsep=0pt,outer sep=0pt] (#1) {};}
\NewDocumentCommand{\caution}{O{c}O{BrickRed}O{Caution!}m}{%
\stepcounter{mycaution}%
\tikzmark{\themycaution}%
\if#1b\relax
\renewcommand\pointeranchor{mybox\themycaution.south east}%
\renewcommand\boxanchor{south east}%
\setlength\boxvshift{-10pt}%
\setlength\uppertrianglecorner{13pt}%
\else
\if#1t\relax
\renewcommand\pointeranchor{mybox\themycaution.north east}%
\renewcommand\boxanchor{north east}%
\setlength\boxvshift{10pt}%
\setlength\uppertrianglecorner{-7pt}%
\else
\if#1c\relax
\renewcommand\pointeranchor{mybox\themycaution.east}%
\renewcommand\boxanchor{east}%
\setlength\boxvshift{0pt}%
\setlength\uppertrianglecorner{3pt}%
\fi\fi\fi%
\begin{tikzpicture}[remember picture,overlay]
\node[draw=#2,anchor=\boxanchor,xshift=-\marginparsep,yshift=\boxvshift]
(mybox\themycaution)
at ([yshift=3pt]current page text area.west|-\themycaution)
{\parbox{\marginparwidth}{\vskip10pt\RaggedRight\small#4}};
\node[fill=white,font=\color{#2}\sffamily,anchor=west,xshift=7pt]
at (mybox\themycaution.north west) {\ #3\ };
\fill[#2]
([yshift=\uppertrianglecorner]\pointeranchor) --
([yshift=\uppertrianglecorner-3pt,xshift=3pt]\pointeranchor) --
([yshift=\uppertrianglecorner-6pt]\pointeranchor) -- cycle;
\end{tikzpicture}%
}
\newcommand\Test{Nulla malesuada porttitor diam. Donec felis erat, congue non, volutpat at, tincidunt tristique, libero. Vivamus viverra fermentum felis. Donec nonummy pellentesque ante. Phasellus adipiscing
semper elit.}
\begin{document}
\lipsum*[4]\caution[t]{\Test}\lipsum[3]\par\bigskip
\lipsum*[4]\caution[c][cyan!80!black]{\Test}\lipsum[3]\par\bigskip
\lipsum*[4]\caution[b][orange][Defcon 5!]{\Test}\lipsum[3]
\end{document}
I tried to improve Gonzalo Medina's code to be able to use two-sided documents.
The four aguments (the first three are optional and the last one is mandatory) are the same than in Gonzalo Medina's code.
I have tried to do my best so that the pointer is facing the text wich was juste before \caution
(this is the reason why my MWE is so long, I had to get rid of the \lipsum
and paste the whole text to put a \caution
in the middle).
In this way, chosing b
, t
or c
for the first argument not only determines the place of the pointer inside the box, but also the placement of the box with respect to the text around the \caution
command.
Furthermore, I recommand using \caution
inside \marginnote
to avoid splitting the paragraph around \caution
.
I tried this code with book
and tufte-book
classes and it seems to work quite fine. However, the use of ifoddpage
needs two or three compilations with pdfLaTeX
\documentclass[twoside,10pt]{book}
\usepackage[dvipsnames]{xcolor}
\usepackage{ragged2e}
\usepackage{xparse}
\usepackage[framemethod=tikz]{mdframed}
\usepackage{tikzpagenodes}
\usepackage{lipsum}
\usepackage{ifoddpage}
\usepackage[fulladjust]{marginnote}
\newcounter{mycaution}
\newlength\trianglexshift
\newlength\boxhshift
\newlength\boxvshift
\newlength\noteheight
\newlength\uppertrianglecorner
\newcommand\side{}
\newcommand\boxanchor{}
\newcommand\otherside{}
\newcommand\pointeranchor{}
\newcommand\tikzmark[1]{%
\tikz[remember picture,overlay]\node[inner xsep=0pt,outer sep=0pt] (#1) {};}
\NewDocumentCommand{\caution}{O{c}O{BrickRed}O{Caution!}m}{%
%
\checkoddpage
\ifoddpageoroneside
\setlength\trianglexshift{-3pt}
\setlength\boxhshift{\marginparsep}
\renewcommand{\side}{west}
\renewcommand{\otherside}{east}
\else
\setlength\trianglexshift{3pt}
\setlength\boxhshift{-\marginparsep}
\renewcommand{\side}{east}%
\renewcommand{\otherside}{west}
\fi
\settoheight{\noteheight}{\parbox{\marginparwidth}{\RaggedRight\small#4}}
\stepcounter{mycaution}%
\tikzmark{\themycaution}%
\if#1b\relax
\renewcommand\pointeranchor{mybox\themycaution.south \side}%
\renewcommand\boxanchor{south \side}%
\setlength\boxvshift{\noteheight}%
\addtolength\boxvshift{0.7\baselineskip}
\setlength\uppertrianglecorner{13pt}%
\else
\if#1t\relax
\renewcommand\pointeranchor{mybox\themycaution.north \side}%
\renewcommand\boxanchor{north \side}%
\setlength\boxvshift{-\noteheight}%
\addtolength\boxvshift{1.3\baselineskip}
\setlength\uppertrianglecorner{-7pt}%
\else
\if#1c\relax
\renewcommand\pointeranchor{mybox\themycaution.\side}%
\renewcommand\boxanchor{\side}%
\setlength\boxvshift{\baselineskip}%
\setlength\uppertrianglecorner{3pt}%
\fi\fi\fi%
\begin{tikzpicture}[remember picture,overlay]
\node[draw=#2,anchor=\side,xshift=\boxhshift,yshift=\boxvshift]
(mybox\themycaution)
at ([yshift=3pt]current page text area.\otherside|-\themycaution)
{\parbox{\marginparwidth}{\vskip10pt\RaggedRight\small#4}};
\node[fill=white,font=\color{#2}\sffamily,anchor=west,xshift=7pt]
at (mybox\themycaution.north west) {\ #3\ };
\fill[#2]
([yshift=\uppertrianglecorner]\pointeranchor) --
([yshift=\uppertrianglecorner-3pt,xshift=\trianglexshift]\pointeranchor) --
([yshift=\uppertrianglecorner-6pt]\pointeranchor) -- cycle;
\end{tikzpicture}}
\newcommand\Test{Nulla malesuada porttitor diam. Donec felis erat, congue non, volutpat at, tincidunt tristique, libero. Vivamus viverra fermentum felis. Donec nonummy pellentesque ante. Phasellus adipiscing
semper elit.}
\begin{document}
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut purus elit,
vestibulum ut, placerat ac, adipiscing vitae, felis. Curabitur dictum gravida
mauris. Nam arcu libero, nonummy eget, consectetuer id, vulputate a, magna.
Donec vehicula augue eu neque\marginnote{\caution[t][cyan!80!black]{\Test}}. Pellentesque habitant morbi tristique senectus
et netus et malesuada fames ac turpis egestas. Mauris ut leo. Cras viverra
metus rhoncus sem. Nulla et lectus vestibulum urna fringilla ultrices. Phasellus
eu tellus sit amet tortor gravida placerat. Integer sapien est, iaculis in, pretium
quis, viverra ac, nunc. Praesent eget sem vel leo ultrices bibendum. Aenean
faucibus. Morbi dolor nulla, malesuada eu, pulvinar at, mollis ac, nulla. Cur-
abitur auctor semper nulla. Donec varius orci eget risus. Duis nibh mi, congue
eu, accumsan eleifend, sagittis quis, diam. Duis eget orci sit amet orci dignissim
rutrum.
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut purus elit,
vestibulum ut, placerat ac, adipiscing vitae, felis. Curabitur dictum gravida
mauris. Nam arcu libero, nonummy eget, consectetuer id, vulputate a, magna.
Donec vehicula augue eu neque. Pellentesque habitant morbi tristique senectus
et netus et malesuada fames ac turpis egestas. Mauris ut leo. Cras viverra
metus rhoncus sem. Nulla et lectus vestibulum urna fringilla ultrices. Phasellus
eu tellus sit amet tortor gravida placerat. Integer sapien est, iaculis in, pretium
quis, viverra ac, nunc. Praesent eget sem vel leo ultrices bibendum. Aenean
faucibus. Morbi dolor nulla, malesuada\marginnote{\caution{\Test}} eu, pulvinar at, mollis ac, nulla. Cur-
abitur auctor semper nulla. Donec varius orci eget risus. Duis nibh mi, congue
eu, accumsan eleifend, sagittis quis, diam. Duis eget orci sit amet orci dignissim
rutrum.
Quisque ullamcorper placerat ipsum. Cras nibh. Morbi vel justo vitae lacus
tincidunt ultrices. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. In
hac habitasse platea dictumst. Integer tempus convallis augue. Etiam facilisis.
Nunc elementum fermentum wisi. Aenean placerat. Ut imperdiet, enim sed
gravida sollicitudin, felis odio placerat quam, ac pulvinar elit purus eget enim.
Nunc vitae tortor. Proin tempus nibh sit amet nisl. Vivamus quis tortor vitae
risus porta vehicula.
\lipsum[3]\par\bigskip
\newpage
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut purus elit,
vestibulum ut, placerat ac, adipiscing vitae, felis. Curabitur dictum gravida
mauris. Nam arcu libero, nonummy eget, consectetuer id, vulputate a, magna.
Donec vehicula augue eu neque. Pellentesque habitant morbi tristique senectus
et netus et malesuada fames ac turpis egestas. Mauris ut leo. Cras viverra
metus rhoncus sem. Nulla et lectus vestibulum urna fringilla ultrices. Phasellus
eu tellus sit amet tortor gravida placerat. Integer sapien est, iaculis in, pretium
quis, viverra ac, nunc. Praesent eget sem vel leo ultrices bibendum. Aenean
faucibus. Morbi dolor nulla, malesuada eu, pulvinar at, mollis ac, nulla. Cur-
abitur auctor semper nulla\marginnote{\caution[b][ForestGreen][Nice !]{\Test}}. Donec varius orci eget risus. Duis nibh mi, congue
eu, accumsan eleifend, sagittis quis, diam. Duis eget orci sit amet orci dignissim
rutrum.
Quisque ullamcorper placerat ipsum. Cras nibh. Morbi vel justo vitae lacus
tincidunt ultrices. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. In
hac habitasse platea dictumst. Integer tempus convallis augue. Etiam facilisis.
Nunc elementum fermentum wisi. Aenean placerat. Ut imperdiet, enim sed
gravida sollicitudin, felis odio placerat quam, ac pulvinar elit purus eget enim.
Nunc vitae tortor. Proin tempus nibh sit amet nisl. Vivamus quis tortor vitae
risus porta vehicula.
\end{document}
An odd page
An even page
REVISED TO INCLUDE BOTH MARGINS! The first mandatory argument is a l
or a r
denoting in which margin the note is to be placed. The second argument is the note. REVISED to allow an optional argument that specifies the upward shift of the box relative to the unchanging arrow pointer.
In my example shown below, I shift the left box up 2ex relative to the default position. In the right box, I leave it at its default position.
EDITED to upgrade the syntax by replacing the deprecated \topinset
macro with its \stackinset
equivalent.
\documentclass{article}
\usepackage{xcolor}
\usepackage{stackengine}
\usepackage{lipsum}
\usepackage{MNsymbol}
\usepackage{graphicx}
\newcommand*\caution[3][0pt]{%
\if l#2\reversemarginpar\def\pointer{\filledmedtriangleright}%
\def\stackalignment{r}\fi%
\if r#2\normalmarginpar\def\pointer{\filledmedtriangleleft}%
\def\stackalignment{l}\fi%
\marginpar{%
\stackinset{\stackalignment}{-2ex}{t}{3ex+#1}{%
\scalebox{1.5}{\textcolor{yellow}{$\pointer$}}}{%
\belowbaseline[-1.5\baselineskip-#1]{%
\stackengine%
{-5pt}%
{\fcolorbox{yellow}{white}{\parbox{1.8cm}%
{\vspace{3pt}\raggedright#3}}}%
{~\colorbox{white}{\sffamily Caution}}%
{O}%
{l}%
{F}%
{F}%
{S}%
}%
}%
}%
}
\begin{document}
\lipsum[1-2]
this is a\caution[2ex]{l}{some text for the caution box} test
\lipsum[3]
This is another test\caution{r}{another caution box test testing the
right side}
\lipsum[4]
\end{document}
and here's the close up: