2

I would like to write an environment to achieve the following:

  1. having a vertical rule on the left that spans the whole text height, with a symbol in the margin (for instance a danger sign),
  2. being breakable across pages in case the content is too long to fit on the current one,
  3. not disturbing the main text flow. That is, the environment content should be typeset the same as it would have been without using the environment.

I managed to implement 1 and 2, and mostly 3. However, I am not able to get consistent behavior of the upper and lower spacing of my environment.

Here are two possible solutions that I came up with, as a MWE. The first one relies on the framed package, the second one on the tcolorbox package. The first one passes the upper spacing test, but not the lower spacing one. The second one passes none.

The issue is that the preceding material may extend (or not) below the baseline of the last preceding line. And the same applies for the framed content. As a result, the height of the framed content or its following material is "visually wrong", as it is higher than expected and breaks the text flow. I would like the whole text to appear as if it was typeset naturally, with even distance between the base lines (assuming there is nothing to disturb them, as in display equations).

I cannot figure a way to automatically and reliably address this issue. As far as I can tell, the framed package doe not offer a way to know the depth of the last line of the framed content. And the after skip option of tcolorbox does not help either.

Actually, there are even more issues, not shown here, in some situations when glue and elastic vertical length are involved (for instance, when the distance between paragraphs is stretched to fill the page).

I must admit this is not a big issue, but I would like to know if someone can think of a working solution.

\documentclass[twoside]{article}

\usepackage{lipsum,multicol}

\columnsep=1.3cm

% Here we define "framedattention" environment

\usepackage{framed,ifoddpage,calc,bclogo}

\usepackage[noadjust]{marginnote}

\makeatletter

\newif\iffirstframe

\def\marginwarning{%
  \checkoddpage%
  \ifoddpage\@reversemargintrue\else\@reversemarginfalse\fi%
  \marginnote{\Large\bcattention}%
}

\newenvironment{framedattention}{%
  \global\firstframetrue%
  \def\FirstFrameCommand##1{%
    \global\firstframefalse%
    \marginwarning%
    \hspace{-6pt}\vrule width 2pt\hspace{4pt}%
    \raisebox{-\height+2ex}[2ex][\height-2ex-20ex]{##1}%
    \global\firstframefalse%
  }%
  \def\FrameCommand##1{%
    \iffirstframe%
      \marginwarning%
    \fi%
    \hspace{-6pt}\vrule width 2pt\hspace{4pt}%
    \raisebox{-\height+2ex}{##1}%
  }%
  \setlength\OuterFrameSep{0pt}%
  \MakeFramed{%
%    \unskip%
    \FrameRestore%
  }%
  \ignorespaces%
}{%
  \endMakeFramed%
  \ignorespacesafterend%
}

% Here we define "tcboxattention" environment

\usepackage{tcolorbox}
\tcbuselibrary{skins,breakable}

\newlength\defparindent
\AtBeginDocument{\defparindent=\parindent}

\tcbset{
  parindent/.style={
    before upper={\parindent=\defparindent},
  }
}

\newtcolorbox{tcboxattention}{
  title=\smash{\bcattention},
  blanker,
  breakable,
  parindent,
  boxsep=0pt,
  left=0pt,
  right=0pt,
  top=0pt,
  bottom=0pt,
  after skip=1ex,
  before skip=1ex,
  attach boxed title to top left={yshift=-25pt,xshift=-30pt},
  borderline west={3pt}{0pt}{black},
  left=10pt,
  grow to left by=10pt,
}%

\begin{document}
  \subsection*{Test of the framedattention environment:}

  \begin{multicols}{2}
    This paragraph has 4 lines and the last one ends with letters extending below the baseline: pppppp pppppp pppppp pppppp pppppp

    \begin{framedattention}
      This paragraph uses the framedattention environment. This is a reference for upper spacing.
    \end{framedattention}

    \vfill\strut

    This paragraph has 4 lines and the last one ends with letters NOT extending below the baseline: aaaaaa aaaaaa aaaaaa aaaaaa

    \begin{framedattention}
      This paragraph uses the framedattention environment. It is at the expected position.
    \end{framedattention}

    \vfill\strut
  \end{multicols}

  \begin{multicols}{2}
    \begin{framedattention}
      This paragraph has 4 lines and the last one ends with letters extending below the baseline: pppppp pppppp pppppp pppppp pppppp
    \end{framedattention}

    This paragraph is a reference for lower spacing.

    \vfill\strut

    \begin{framedattention}
      This paragraph has 4 lines and the last one ends with letters NOT extending below the baseline: aaaaaa aaaaaa aaaaaa aaaaaa
    \end{framedattention}

    This paragraph is higher than expected.

    \vfill\strut
  \end{multicols}

  \subsection*{Test of the tcboxattention environment:}

  \begin{multicols}{2}
    This paragraph has 4 lines and the last one ends with letters extending below the baseline: pppppp pppppp pppppp pppppp pppppp

    \begin{tcboxattention}
      This paragraph uses the tcboxattention environment. This is a reference for upper spacing.
    \end{tcboxattention}

    \vfill\strut

    This paragraph has 4 lines and the last one ends with letters NOT extending below the baseline: aaaaaa aaaaaa aaaaaa aaaaaa

    \begin{tcboxattention}
      This paragraph uses the tcboxattention environment. It is higher than expected.
    \end{tcboxattention}

    \vfill\strut
  \end{multicols}

  \begin{multicols}{2}
    \begin{tcboxattention}
      This paragraph has 4 lines and the last one ends with letters extending below the baseline: pppppp pppppp pppppp pppppp pppppp
    \end{tcboxattention}

    This paragraph is a reference for lower spacing.

    \vfill\strut

    \begin{tcboxattention}
      This paragraph has 4 lines and the last one ends with letters NOT extending below the baseline: aaaaaa aaaaaa aaaaaa aaaaaa
    \end{tcboxattention}

    This paragraph is higher than expected.

    \vfill\strut
  \end{multicols}

\end{document}

Here is a screen capture of the resulting PDF. I added horizontal green lines to illustrate the issue. The offset is not big (maybe 1 or 2 millimeters), so maybe you will have to zoom on the image to see it.

Issue

3
  • This problem seems similar to Making mdframed paragraph behave like normal paragraphs
    – siracusa
    Oct 23 '19 at 11:42
  • Thank you, I missed this page! I did not know about the \prevdepth macro. It seems I can fix my issue using it.I am not sure how reputation is working on this site, and I cant figure how to give credit for your answer. Pleas let me know if I need to do something. Meanwhile I will post a working solution below. Oct 23 '19 at 19:48
  • No worries, the comment section is only for giving additional information regarding a post or for people (like me sometimes) who are too lazy to write up a complete answer ;-) If your own answer below is completely satisfying for your use case, you can also accept it by clicking the little check mark, or you could wait for somebody to come up with a better answer.
    – siracusa
    Oct 24 '19 at 11:23
1

A possible solution, based on Making mdframed paragraph behave like normal paragraphs in terms of spacing suggested by siracusa, that uses a modified version of egreg's code.

It seems to work for characters that extend below the baseline (like p), or not (like a), or that go higher (like X), both inside and outside the environment.

\documentclass[twoside]{article}

\usepackage{lipsum,multicol}

\columnsep=1.3cm

\usepackage{tcolorbox,calc,bclogo}
\tcbuselibrary{skins,breakable}

\newlength\defparindent
\AtBeginDocument{\defparindent=\parindent}

\tcbset{
  parindent/.style={
    before upper={\parindent=\defparindent},
  }
}

\newtcolorbox{tcboxattention}[1][]{
  title=\smash{\bcattention},
  blanker,
  breakable,
  parindent,
  boxsep=0pt,
  left=0pt,
  right=0pt,
  top=0pt,
  bottom=0pt,
  after skip=0pt,
  attach boxed title to top left={yshift=-25pt,xshift=-30pt},
  borderline west={3pt}{0pt}{black},
  left=10pt,
  grow to left by=10pt,
  #1
}%

\newlength\prefixheight
\newlength\postfixheight

\newenvironment{attention}{%
  \prefixheight=\dimexpr\dp\strutbox-\prevdepth\relax%
  \begin{tcboxattention}[before skip=\prefixheight]%
    \strut%
    \ignorespaces%
}{%
    \par%
    \global\postfixheight=\prevdepth%
  \end{tcboxattention}%
  \par%
  \vskip\dimexpr-\ht\strutbox-\postfixheight\relax%
  \strut%
  \par%
}

\def\ppp{ppp ppp ppp ppp ppp ppp ppp ppp ppp ppp}
\def\aaa{aaa aaa aaa aaa aaa aaa aaa aaa aaa aaa}
\def\XXX{XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX}

\begin{document}
  \begin{multicols}{2}

    \aaa

    \begin{attention}
      \aaa
    \end{attention}

      \ppp

    \begin{attention}
      \ppp
    \end{attention}

    \XXX

    \begin{attention}
      \XXX
    \end{attention}

    \vfill\strut\columnbreak

    \aaa

    \aaa

    \ppp

    \ppp

    \XXX

    \XXX

    \vfill\strut

  \end{multicols}\vspace{-24pt}\color{red}\hrule
\end{document}

Here is a capture (the red line shows that everything is aligned as expected).

Issue solved

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.