我想编写一个环境来实现以下目标:
- 左侧有一条垂直线,横跨整个文本高度,并在边距中有一个符号(例如危险标志),
- 如果内容太长,当前页面无法容纳,则可以跨页面拆分,
- 不干扰主文本流。也就是说,环境内容的排版应与不使用环境时相同。
我设法实现了 1 和 2,主要是 3。但是,我无法获得环境上下间距的一致行为。
作为 MWE,我想出了以下两种可能的解决方案。第一种依赖于包framed
,第二种依赖于tcolorbox
包。第一种通过了上间距测试,但没有通过下间距测试。第二种没有通过任何测试。
问题是,前面的内容可能会延伸(或不会)到最后一行基线以下。框架内容也是如此。因此,框架内容或其后续内容的高度“在视觉上是错误的”,因为它高于预期并打断了文本流。我希望整个文本看起来就像是自然排版的,基线之间的距离均匀(假设没有任何东西干扰它们,如显示方程式中所示)。
我无法找到一种自动且可靠地解决这个问题的方法。据我所知,该framed
软件包没有提供一种方法来了解框架内容最后一行的深度。而且选项after skip
也tcolorbox
无济于事。
实际上,在涉及粘连和弹性垂直长度的某些情况下(例如,当段落之间的距离被拉伸以填充页面时),还存在更多问题(这里没有显示)。
我必须承认这不是一个大问题,但我想知道是否有人能想到一个可行的解决方案。
\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}
这是生成的 PDF 的屏幕截图。我添加了水平绿线来说明问题。偏移不大(可能只有 1 或 2 毫米),所以您可能需要放大图像才能看到它。
答案1
一种可能的解决方案,基于使 mdframed 段落在间距方面表现得像普通段落建议来自锡拉库萨,使用修改后的版本埃格尔的代码。
它似乎适用于延伸到基线以下(如p
)或不延伸到基线(如a
)的字符,或者延伸到基线以上的字符(如X
),无论是在环境内部还是外部。
\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}
这是一个捕获(红线显示一切都按预期对齐)。