# Automatic / variable vertical alignment within a minipage?

I have defined a new environment that I use to highlight warnings in my text. Here's a minimal example of the code I use:

\documentclass[parskip]{scrartcl}
\usepackage{fourier} % for the bomb
\usepackage{lipsum}

\newenvironment{warning}{%
\begin{minipage}[t][\height][c]{0.12\textwidth}%
{\Huge{\bomb}}%
\end{minipage}%
\begin{minipage}[t]{0.88\textwidth}
\begin{sloppypar}%
}{%
\end{sloppypar}%
\end{minipage}%
\hspace{-\parfillskip}%
}

\begin{document}
\lipsum[1]

\begin{warning}
\lipsum[2]
\end{warning}

\lipsum[3]

\begin{warning}
This is just a short warning.
\end{warning}

\lipsum[4]

\end{document}

This mostly works as intended, at least for longer warnings. If the text of the warning consists of only one or two lines, the vertical alignment of the text next to the symbol starts looking weird. If I change the vertical alignment of the minipages from t to c, the overall spacing improves for the short warnings, but this also changes the longer warnings in what I consider a worse layout. I realize that I could solve this with two distinct environments for short and long warnings, but is there a way to automate this? Like if the contents of the right-hand column exceed a height of ..., use this alignment, else use the other one?

(I'll also accept pointers to packages that provide a similar highlighting in a more robust/professional/cool way :-))

A modification of my answer to Aligning images in the marginal notes based on a specific paragraph height rule

Caveat: warnings should be one paragraph only for the measurement to be correct.

\documentclass[a4paper]{article}
\usepackage[top=2.5cm,bottom=2.5cm]{geometry}
\usepackage{environ}
\usepackage{fourier}

\makeatletter
\NewEnviron{warning}{%
%% Count the number of lines
\setbox\z@=\vbox{\hsize=.88\textwidth\BODY\par
\xdef\vw@nlines{\the\prevgraf}}%
%% Typeset the warning; .12+.88=1
\begin{list}{}{%
\leftmargin=.12\textwidth
\clubpenalties=4 10000 10000 10000 0
}%
\ifcase\vw@nlines\or % no empty paragraphs
\vw@placefigure{0}%
\or
\vw@placefigure{.5}%
\else
\vw@placefigure{1}%
\fi
\BODY
\end{list}%
}
\def\vw@placefigure#1{\item[\leavevmode\smash{\makebox[0pt][r]{%
\vbox{\hbox{\Huge\bomb}
\vskip-9pt % half the height of the bomb
\vskip-#1\baselineskip % shift down
}}}]}
\makeatother

\usepackage{lipsum}

\begin{document}
\lipsum[3]

\begin{warning}
\lipsum[3]
\end{warning}

\lipsum[3]

\begin{warning}
This is just a short warning.
\end{warning}

\lipsum[3]

\begin{warning}
A two line\\
warning
\end{warning}

\lipsum[3]

\begin{warning}
A three\\
line\\
warning
\end{warning}

\begin{warning}
\lipsum[3]
\end{warning}

\end{document}

This allows also for page breaks, but only after three lines of the warning text.

• Just out of curiosity - why the \makeatletter and \makeatother instructions in this case? There aren't any @s in this code, or am I missing something? – vwegert Jul 17 '13 at 13:59
• @vwegert Oh, there were @'s in the original code. I can put some, if you prefer. ;-) – egreg Jul 17 '13 at 14:01

To get what you wanted, I had to change the warning environment to \warningmacro, since I needed to measure the height of the text in order to decide where to place the bomb. Basically, I place it appropriately for a one-line warning and then start shifting it down 70% of the text depth, until I reach a maximum limit of shift. The two parameters to play with are the length \reflength and the scalar value of \shiftmult, currently set at 22pt and 0.7. The maximum vertical shift of the bomb will be \shiftmult\reflength.

\documentclass[parskip]{scrartcl}
\usepackage{fourier} % for the bomb
\usepackage{lipsum}
\usepackage{stackengine}
\newlength\warndepth

\newsavebox\warnpar
\newlength\reflength
\setlength{\reflength}{22pt}
\def\shiftmult{0.7}
\newcommand\warningmacro[1]{%
\sbox\warnpar{\parbox[t]{0.88\textwidth}{%
\begin{sloppypar}%
#1%
\end{sloppypar}%
}
}%
\def\bigbomb{\Huge{\bomb}}%
\setlength\warndepth{\depthof{\usebox{\warnpar}}}%
\ifdim\warndepth>\reflength \setlength\warndepth{\reflength}\fi%
\belowbaseline[\shiftmult\warndepth-1.5\baselineskip]{%
\makebox[.12\textwidth][l]{\bigbomb}%
}%
\usebox{\warnpar}%
\hspace{-\parfillskip}%
}

\begin{document}
This is normal text%\lipsum[1]

\warningmacro{%
Let's see what happens when we get a two-line warning
Let's see what happens when we get a two-line warning
}

This is more normal text

\warningmacro{%
Let's see what happens when we get a three-line warning
Let's see what happens when we get a three-line warning
Let's see what happens when we get a three-line warning
Let's see what happens when we get a three-line warning
}

This is more normal text

\warningmacro{%
\lipsum[2]
}

\lipsum[3]

\warningmacro{%
This is just a short warning.
}

\lipsum[4]

\end{document}

• A good solution as well, but I'd have to edit about 19 kLOLC to switch from environments to warnings... – vwegert Jul 17 '13 at 14:41
• @vwegert That's what search and replace is for in editors ;^) – Steven B. Segletes Jul 17 '13 at 14:50