2

I am using the caption package to style my captions. Consider a small wrapfigure which has a wide caption that is broken into n lines.

I want the first n-1 lines of the caption to use justification=justified, whereas the last line (which does not fill the width available to the caption) shall be raggedleft.

Optimally I would love to be able to specify a different justification for the last line of a caption, independently of the the floating environment, e.g. by specifying \captionsetup{justification=justified, lastlinejustification=raggedleft} or some other value.

I know that the caption package provides centerlast, so something like raggedleftlast would also be great ;)

2 Answers 2

4

I know why it works.

A variation on John Kormylo's answer, without redefining internals of caption, but rather adding a justification mode.

\documentclass{article}
\usepackage{caption}
\usepackage{wrapfig}
\usepackage{lipsum}

\DeclareCaptionOptionNoValue*{rjustified}{%
  \caption@setformat{plain}%
  \caption@setjustification{rjustified}%
}
\DeclareCaptionJustification{rjustified}{\rjustified}
\makeatletter
\newcommand\rjustified{%
  \let\\\@fillcr
  \leftskip\z@\@plus 1fil
  \rightskip\z@\@plus -1fil
  \parfillskip\z@\@plus 1fil\relax
}
% don't bother with this if you don't plan to use \\ in a caption
\protected\def\@fillcr{%
  \let \reserved@e \relax
  \let \reserved@f \relax
  \@ifstar{\let \reserved@e \vadjust \let \reserved@f \nobreak
             \@xnewlinefill}%
  \@xnewlinefill}
\def\@xnewlinefill{\@ifnextchar[% ] bracket matching
                  \@newlinefill
                 {\@gnewlinefill\relax}}
\def\@newlinefill[#1]{\let \reserved@e \vadjust
                   \@gnewlinefill {\vskip #1}}
\def\@gnewlinefill #1{%
  \ifvmode
    \@nolnerr
  \else
    \unskip \reserved@e {\reserved@f#1}\nobreak \hfill \break
  \fi}
%%%% end of `no bother with this'
\makeatother

\begin{document}

\begin{wrapfigure}{l}{4cm}
\centering
\captionsetup{justification=rjustified}
\fbox{\rule{3cm}{0pt}\rule{0pt}{3cm}}
\caption{\lipsum[1][2-3]}
\end{wrapfigure}

\lipsum[1-2]

\end{document}

enter image description here

If you don't plan to use \\ in captions when justification=rjustified is active, remove the \let\\\@fillcr instruction and the lines in the code above where \@fillcr is defined mimicking \@normalcr. Surely \@centercr is not what you want here.

How does it work? Every line in a paragraph has glue at either side of amount \leftskip and \rightskip respectively. For a normal (justified) paragraph, they are both set to zero.

Here the former is set to zero but with positive infinite stretchability and the latter to zero with negative infinite stretchability. Therefore they normally cancel each other and nothing strange happens. However, TeX adds \parfillskip glue to the last line of a paragraph; its value is normally 0pt plus 1fil (the same as is set here, just for safety). This glue will cancel the negative infinite stretchability of \rightskip on the last line only, so in this line the positive stretchability of \leftskip will act and move the last line to be flush right.

Of course you don't want to have more than one paragraph in the caption.

The \@fillcr business is a variant of \@normalcr where \hfill is used instead of \hfil, so the higher degree of infinity will prevail over the fil units of \leftskip and \rightskip.

1
  • This is great! Thansk a lot for the code AND the explanation. Indeed I did not intend to use \\ in the caption, so in the end it is the same as John's original answer except for providing rjustified. I accepted this answer, since it is slightly more general
    – Elarion
    Jul 30, 2020 at 6:27
2

I don't know why it works, but it does.

\documentclass{article}
\usepackage{caption}
\captionsetup{justification=centerlast}
\usepackage{lipsum}% MWE only

\makeatletter
\renewcommand\centerlast{%
  \let\\\@centercr
  \leftskip\z@\@plus 1fil%
  \rightskip\z@\@plus -1fil%
  \parfillskip\z@\@plus 1fil\relax}
\makeatother

\begin{document}

\begin{figure}
\caption{\LipsumPar{2}}
\end{figure}

\end{document}

demo

2
  • Thanks alot John! It indeed works perfectly! However I also am also using centerlast at another place of the document, so I accepted Egreg's answer and upvoted yours
    – Elarion
    Jul 30, 2020 at 6:28
  • I was hoping someone like @egreg would step up. Adding package options is outside my comfort zone. Jul 30, 2020 at 13:48

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.