# Nested breakable boxes with line on the left (any package)

I'm trying to create an environment like quotation, but with a line on the left. I would also like it to support multiple paragraphs, footnotes, math environments and floats (basically you should be able to wrap it around any, or most content and it should just work).

The difficult thing is that I want it to handle pagebreaks, even when nested. From the TeXFAQ entry about breaking boxes of text, I know it is possible to do this with the boites package, but it breaks floats and footnotes, sadly, so this is not an option for me. There have been similar questions before, but for whole boxes instead of only left lines. I'm not sure if this question might be easier to answer. I am also aware that this is apparently not possible to solve using the framed, mdframed or tcolorbox packages (see the package documentations).

There is a similar question about mdframed specifically, instead of about the problem in general, but the boxes in the answer do not work with arbitrary content. (previous question was marked as duplicate, this is to clarify why I think it isn't)

Can this be done?

Example:

Example code adapted from a similar question:

\documentclass{article}

\usepackage{framed}
\usepackage[parfill]{parskip}

\newenvironment{quotationb}%
{\begin{leftbar}}%
{\end{leftbar}}

\begin{document}

\begin{quotationb}
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
\begin{quotationb}
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
\begin{quotationb}
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
\end{quotationb}
Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
\end{quotationb}
Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
\end{quotationb}
\end{document}

• Possible approach: Two pass, first pass saves start and end position and pages of each environment, on second pass draw the lines based on these saved positions using the background picture of the shipout hooks. All the environment controls of the typeout is the increase of the left margin. Dec 4, 2021 at 14:07
• Your example image has no top or bottom margin; where would you want the footnote text to go? Will no pages have these margins? I don't quite understand what good wrapping floats in this sort of environment would be. I imagine you want the floats to appear in the indented level they were defined in which seems to defeat the whole point of floating.
– Dan
Dec 6, 2021 at 23:13
• @Dan for these cases, the environment should behave like the quotation environment. So footnotes should go at the bottom of the page as usual and floats should be placed depending on the placement specifier h/t/c etc. The margins of pages shouldn't matter much for the behaviour and should be user definable. Dec 6, 2021 at 23:52

The following is a sufficient option. It uses eso-pic to draw the vertical rules, allows for nesting and adjustment of the indentation and rule width.

\documentclass{article}

\usepackage{lipsum}
\usepackage{changepage,eso-pic}
\usepackage[savepos,abspage,user]{zref}

\newcounter{newleftbar}
\newlength{\leftbarindent}
\newlength{\leftbarwidth}
\setlength{\leftbarwidth}{2pt}

\makeatletter
\NewDocumentEnvironment{leftbar}{ O{2em} }{%
\setlength{\parindent}{0pt}%
\def\@leftbarindent{#1}%
\edef\leftbarnest{\thenewleftbar}%
\stepcounter{newleftbar}% New leftbar environment
\edef\theleftbar{\thenewleftbar}%
\leavevmode% Start paragraph
\zsavepos{leftbar-\leftbarnest-\theleftbar-top}% Save position of left bar top
\zlabel{leftbar-\leftbarnest-\theleftbar-top-page}% Save page of left bar top
% Store left bar top's text block top/bottom
\noexpand\AtTextUpperLeft{\noexpand\zsavepos{leftbar-\leftbarnest-\theleftbar-ftt}}%
\noexpand\AtTextLowerLeft{\noexpand\zsavepos{leftbar-\leftbarnest-\theleftbar-ftb}}%
}%
\noexpand\ifnum\noexpand\zref@extractdefault{leftbar-\leftbarnest-\theleftbar-top-page}{abspage}{0}=\noexpand\zref@extractdefault{leftbar-\leftbarnest-\theleftbar-bottom-page}{abspage}{0}
% Single page left bar
\noexpand\ifnum\noexpand\zref@extractdefault{leftbar-\leftbarnest-\theleftbar-top-page}{abspage}{0}=\noexpand\arabic{abspage}
\noexpand\put(\dimexpr\zposx{leftbar-\leftbarnest-\theleftbar-top}sp-#1,\dimexpr\zposy{leftbar-\leftbarnest-\theleftbar-bottom}sp-.2\baselineskip){%
\noexpand\rule{\leftbarwidth}{\dimexpr\zposy{leftbar-\leftbarnest-\theleftbar-top}sp-\zposy{leftbar-\leftbarnest-\theleftbar-bottom}sp+\baselineskip}}%
\noexpand\fi
\noexpand\fi
\noexpand\ifnum\noexpand\zref@extractdefault{leftbar-\leftbarnest-\theleftbar-top-page}{abspage}{0}<\noexpand\zref@extractdefault{leftbar-\leftbarnest-\theleftbar-bottom-page}{abspage}{0}
% Multipage left bar
\noexpand\ifnum\noexpand\zref@extractdefault{leftbar-\leftbarnest-\theleftbar-top-page}{abspage}{0}=\noexpand\arabic{abspage}
% First page bar
\noexpand\put(\dimexpr\zposx{leftbar-\leftbarnest-\theleftbar-top}sp-#1,\zposy{leftbar-\leftbarnest-\theleftbar-ftb}sp){%
\noexpand\rule{\leftbarwidth}{\dimexpr\zposy{leftbar-\leftbarnest-\theleftbar-top}sp-\zposy{leftbar-\leftbarnest-\theleftbar-ftb}sp+.8\baselineskip}}%
\noexpand\fi
\noexpand\ifnum\noexpand\arabic{abspage}>\noexpand\zref@extractdefault{leftbar-\leftbarnest-\theleftbar-top-page}{abspage}{0}
\noexpand\ifnum\noexpand\arabic{abspage}<\noexpand\zref@extractdefault{leftbar-\leftbarnest-\theleftbar-bottom-page}{abspage}{0}
% Middle page bar
\noexpand\put(\dimexpr\zposx{leftbar-\leftbarnest-\theleftbar-top}sp-#1,\dimexpr\zposy{leftbar-\leftbarnest-\theleftbar-ftb}sp-.2\baselineskip){%
\noexpand\rule{\leftbarwidth}{\dimexpr\zposy{leftbar-\leftbarnest-\theleftbar-ftt}sp-\zposy{leftbar-\leftbarnest-\theleftbar-ftb}sp}}%
\noexpand\fi
\noexpand\fi
\noexpand\ifnum\noexpand\zref@extractdefault{leftbar-\leftbarnest-\theleftbar-bottom-page}{abspage}{0}=\noexpand\arabic{abspage}
% Last page bar
\noexpand\put(\dimexpr\zposx{leftbar-\leftbarnest-\theleftbar-top}sp-#1,\dimexpr\zposy{leftbar-\leftbarnest-\theleftbar-bottom}sp-.2\baselineskip){%
\noexpand\rule{\leftbarwidth}{\dimexpr\zposy{leftbar-\leftbarnest-\theleftbar-ltt}sp-\zposy{leftbar-\leftbarnest-\theleftbar-bottom}sp+.2\baselineskip}}%
\noexpand\fi
\noexpand\fi
}}\x
\ignorespaces
}{%
\zlabel{leftbar-\leftbarnest-\theleftbar-bottom-page}% Save page of let bar bottom
\zsavepos{leftbar-\leftbarnest-\theleftbar-bottom}% Save position of left bar bottom
% Store left bar bottom's text block top/bottom
\noexpand\AtTextUpperLeft{\noexpand\zsavepos{leftbar-\leftbarnest-\theleftbar-ltt}}%
\noexpand\AtTextLowerLeft{\noexpand\zsavepos{leftbar-\leftbarnest-\theleftbar-ltb}}%
}}\x%
}
\makeatother

\begin{document}

\lipsum[1]

\begin{leftbar}
\lipsum[2]

\begin{leftbar}[1em]
\lipsum[3-12]
\end{leftbar}

\lipsum[13]
\end{leftbar}

\lipsum[14]

\begin{leftbar}[5pt]
\lipsum[15]
\end{leftbar}

\lipsum[16]

\begin{leftbar}
\vspace{-\baselineskip}
\begin{leftbar}
\lipsum[17]
\end{leftbar}
\end{leftbar}

\lipsum[18]

\begin{leftbar}
\lipsum[19]
\begin{leftbar}
\lipsum[20]
\end{leftbar}
\end{leftbar}

\lipsum[21]

\begin{leftbar}
\lipsum[22]
\begin{leftbar}
\lipsum[23]
\begin{leftbar}
\lipsum[24]
\begin{leftbar}
\lipsum[25]
\end{leftbar}
\lipsum[26]
\end{leftbar}
\lipsum[27]
\end{leftbar}
\lipsum[28]
\end{leftbar}

\lipsum[29]

\end{document}


zref is used to capture the position of the start and end of the leftbar text block and absolute page number to identify whether the leftbar is on a single page or has to span multiple pages. In the latter case, the bar is split into a "first page bar", "middle page bar" (possibly non-existent) and a "last page bar".

This should work sufficiently for a oneside document, or twoside with similar margins. If the text blocks are offset (like in twoside mode), there may be placement issues, or the code has to be updated to accommodate for that.

Not much is done to check for nesting without content at some level, so manual vertical adjustment is required. Also, multiply consecutive closures (\end{leftbar} \end{leftbar}) may have some misalignment due to spacing from adjustwidth.

• Wow...Very nice and interesting... Dec 7, 2021 at 12:57
• Thank you for this amazing answer. I was able to get it to work with twoside mode (will post modified code later) by making the line placement relative to the current page's \AtTextUpperLeft position. The other limitations you mention are no big deal to me. However, I noticed a major bug with floats and footnotes: if you add A footnote\footnote{This collides with the leftbars}. \begin{figure}[b!] \textcolor{lightgray}{\rule{2cm}{2cm}} \caption{This also does} \end{figure} directly after \begin{document}, the leftbars extend too far downwards. Dec 8, 2021 at 23:25
• @Werner I also think it still works if you remove \leftbarnest everywhere, right? Dec 8, 2021 at 23:27
• @Matthias: Of course, there's no consideration made for floats or footnotes that are set within the text block, so the lines will overrun those.
– Werner
Dec 9, 2021 at 0:06
• @Werner Do you know how one would do this to prevent overrunning? Dec 11, 2021 at 12:16