4
  • When you use the allowframebreaks option in beamer then you get additional frames if the content is too high for one frame.
  • The vertical spacing gets disturbed when you use a list (itemize, enumerate, description), for example, see the following animation. I used the t option (for top alignment) for the frame.

enter image description here

\documentclass[aspectratio=169]{beamer}


\begin{document}

\begin{frame}[t,allowframebreaks]
\frametitle{Frame Title}
\setlength{\mylength}{\baselineskip}
\begin{itemize}
\item Test
\item Test
\item Test
\item Test
\item Test
\item Test
\item Test
\item Test
\item Test
\item Test
\item Test
\item Test
\item Test
\item Test
\item Test
\item Test
\item Test
\end{itemize}

\end{frame}

\begin{frame}[t,allowframebreaks]
\frametitle{Frame Title}

Text\\
Text\\
Text\\
Text\\
Text\\
Text\\
Text\\
Text\\
Text\\
Text\\
Text\\
Text\\
Text\\
Text\\
Text\\
Text\\
Text\\
Text\\
Text\\
Text\\
Text\\
Text\\
Text\\
Text\\
Text\\

\end{frame}

\end{document}
  • I thought of a solution, when I read this question where they explain the different length in lists.
  • The main idea is to check if the current frame is not the first frame of a frame continuation and add the needed vertical space.
  • I thought that \topsep is the needed length but apparently, it is not quite right.
  • It ist almost perfect but it still "dances" a little bit.
  • Which additional length do I need?
  • Here's the animation and the used code.

enter image description here

\documentclass[aspectratio=169]{beamer}

\setbeamertemplate{frametitle continuation}{%
    (\insertcontinuationcount)%
    \ifnum\insertcontinuationcount>1%
    \vspace*{\topsep}%
    \else%
    %
    \fi%
}

\begin{document}

\begin{frame}[t,allowframebreaks]
\frametitle{Frame Title}

\begin{itemize}
\item Test
\item Test
\item Test
\item Test
\item Test
\item Test
\item Test
\item Test
\item Test
\item Test
\item Test
\item Test
\item Test
\item Test
\item Test
\item Test
\item Test
\end{itemize}

\end{frame}

\end{document}

Related

Definition of \itemize in beamer

In beamerbaselocalstructure.sty I found

\renewcommand{\itemize}[1][]{%
  \beamer@ifempty{#1}{}{\def\beamer@defaultospec{#1}}%
  \ifnum \@itemdepth >2\relax\@toodeep\else
    \advance\@itemdepth\@ne
    \beamer@computepref\@itemdepth% sets \beameritemnestingprefix
    \usebeamerfont{itemize/enumerate \beameritemnestingprefix body}%
    \usebeamercolor[fg]{itemize/enumerate \beameritemnestingprefix body}%
    \usebeamertemplate{itemize/enumerate \beameritemnestingprefix body begin}%
    \list
      {\usebeamertemplate{itemize \beameritemnestingprefix item}}
      {\def\makelabel##1{%
          {%
            \hss\llap{{%
                \usebeamerfont*{itemize \beameritemnestingprefix item}%
                \usebeamercolor[fg]{itemize \beameritemnestingprefix item}##1}}%
          }%
        }%
      }
  \fi%
  \beamer@cramped%
  \raggedright%
  \beamer@firstlineitemizeunskip%
}

But I do not understand where the different kinds of spaces are defined that cause the "dancing".

"Evil" Stuff in beamer

Motivated by the comment of @cfr I searched the beamer documentation for "evil" stuff -- this is what I have found (beamer guide version 3.41):

  • Do not use subsubsections, they are evil.
  • Never ever use the evil option shrink.
  • Using this [again shrink] option is very evil.
  • The use of this [allowframebreaks] option is evil.
  • 2
    You are aware that use of this option is considered evil? The only thing I use it for is a list of references, when people have the opportunity to get the references from a copy of the slides later or something like that. (That is, I don't present the references, but they are at the end if people download the slides later.) Other than that, allowframebreaks just shouldn't be used. – cfr Mar 10 '17 at 0:49
  • 1
    The thing is that there are standard ways to avoid things 'dancing', but I doubt they work with allowframebreaks because this option isn't at all intended for use with content you are actually going to present on screen. – cfr Mar 10 '17 at 0:51
  • 2
    It is in the manual: The use of this option is \emph{evil}. (page 60) – cfr Mar 10 '17 at 19:58
  • 1
    Corresponding but report: github.com/josephwright/beamer/issues/506 – user36296 Sep 22 '18 at 13:42
  • 1
    @Dr.ManuelKuehner It is only fixed for normal text, not for lists – user36296 Sep 22 '18 at 20:58
3

The difference comes from the following scenario:

\documentclass{article}


\begin{document}


%\baselineskip0pt
%\lineskip0pt


\vbox{Case1: a vbox}
and then a natural paragraph


\bigskip


\newbox\tempvbox
\setbox\tempvbox=\vbox{and then some vbox content}
\vbox{Case2: a vbox}
\box\tempvbox


\bigskip


\setbox\tempvbox=\vbox{and then some unboxed content}
\vbox{Case3: a vbox}
\unvbox\tempvbox


\end{document}

In the first two cases, the space between lines is determined by \baselineskip. By changing \baselineskip you can see the space varying.

In the third case, there is basically no space and the two boxes are put side by side. It looks like when both \baselineskip and \lineskip are zero.


Go to beamer. In the definition of the environment beamer@frameslide, there is a \vbox

\vskip-\parskip\vbox{}% 

This corresponds to the \vbox{Case1/2/3: a vbox} above.

Following this \vbox is the content of your frame. In this case, there is an \itemize. So the first page looks perfect.

Starting from the second page, the content is extracted by the following line

\setbox\@tempboxa=\vsplit\beamer@framebox to\beamer@autobreakfactor\textheight%

and put back to the page by

\ifbeamer@slidehaszoom\box\beamer@framebox\else\unvbox\beamer@framebox\fi%

This corresponds to the third case above. So starting from the second page the space at the top of the page is insufficient.


Appendix

These macros are involved.

\beamer@collect@@body

  • #1 is the content of the frame. That is, anything between \begin{frame} and \end{frame}
  • #2 should be the string frame. Things will get a little bit tense if you have nested environments.
  • \beamer@envbody is a tokenlist. According to the fifth line, it will store the content of your frame.
\long\def\beamer@collect@@body#1\end#2{%
  \def\test{#1}%
  \edef\beamer@begin@stack{\beamer@push@begins#1\begin\end \expandafter\@gobble\beamer@begin@stack}%
  \ifx\@empty\beamer@begin@stack % This will be true; I do not know what is this for
      \global\beamer@envbody\expandafter{\the\beamer@envbody#1}%
    \def\reserved@a{#2}
    \ifx\reserved@a\beamer@frametext%
      \endgroup%
      \let\@next=\beamer@process@envbody % A little tricky! Note the grouping
      \@checkend{#2}%
    \else%
      % ok, just expand it, presumably it will generate the desired \end{frame}
      \let\@next=\beamer@process@expander%
    \fi
  \else
    \global\beamer@envbody\expandafter{\the\beamer@envbody#1\end{#2}}%
    \let\@next=\beamer@process@envbody%
  \fi
  \@next
}

\beamer@autobreakframe

After beamer reads [allowframebreak], it will realize how to treat this frame. This macro is what beamer will do next.

After \begin{beamer@frameslide}, anything you add will appear at the top of the slide, below the title. (provided that you have a title)

\def\beamer@autobreakframe{%
  \beamer@slideinframe=1\relax%
  \advance\beamer@autobreakcount by1\relax%
  \begin{beamer@frameslide}\relax%
    % if you add anything here, it will appear at the top of the slide
    \bgroup%
    \aftergroup\beamer@endautobreak%
    \afterassignment\beamer@checkframetitle%
    \let\beamer@next% gobble opening brace
  }

\beamer@endautobreak

If you add anything before \end{beamer@frameslide}, it will appear at the end of the slide. (But it will be too late)

\def\beamer@endautobreak{\end{beamer@frameslide}%
  \beamer@writeslidentry%
  \ifvoid\beamer@splitbox%
    \let\beamer@next=\beamer@reseteecodes%
  \else%
    \let\beamer@next=\beamer@continueautobreak%
  \fi%
  \beamer@next%
}

\beamer@autobreakframebox

This is the algorithm that beamer uses to split looong contents into several pages.

Before this macro, \beamer@framebox stores the looong contents. After this macro, \beamer@splitbox stores the content that fits a slide/page.

\def\beamer@autobreakframebox{%
  \global\setbox\beamer@splitbox=\box\voidb@x%
  \ifbeamer@autobreak%
    % Ok, frame was overful -> split it!
    \setbox\@tempboxa=\vsplit\beamer@framebox to\beamer@autobreakfactor\textheight% NOTICE THIS LINE
    \global\setbox\beamer@splitbox=\box\beamer@framebox%
    \@tempdima=\ht\beamer@splitbox%
    \ifdim\@tempdima<\beamer@autobreaklastheight%
      \global\beamer@autobreaklastheight=\@tempdima\relax%
    \else%
      \setbox\@tempboxa=\vbox{\unvbox\@tempboxa\unvbox\beamer@splitbox}%
      \global\setbox\beamer@splitbox=\box\voidb@x%
    \fi%
    \setbox\beamer@framebox=\vbox to\textheight{\unvbox\@tempboxa%
      \vskip\beamer@framebottomskipautobreak%
      \ifvoid\beamer@splitbox%
        \ifvoid\beamer@footins%
        \else%
          \begingroup
            \usebeamercolor*[fg]{footnote}%
            \footnoterule%
            \unvbox \beamer@footins%
            \global\setbox\beamer@footins=\box\voidb@x%
          \endgroup  
        \fi%
      \fi%
      \beamer@exitcode%
    }%
  \else%
    \setbox\beamer@framebox=\vbox to\textheight{\unvbox\beamer@framebox%
      \vskip\beamer@framebottomskip%
      \ifvoid\beamer@footins%
      \else%
        \begingroup
          \usebeamercolor*[fg]{footnote}%
          \footnoterule%
          \unvbox \beamer@footins%
          \global\setbox\beamer@footins=\box\voidb@x%
        \endgroup 
      \fi%
      \beamer@exitcode}%
    \global\setbox\beamer@footins=\box\voidb@x%
  \fi%
  }

\beamer@continueautobreak

This is the macro that prints the content to individual slides/pages. Notice the \unvbox in the second line from the bottom.

\def\beamer@continueautobreak{%
  \refstepcounter{framenumber}%
  \expandafter\beamer@frametitletoks\expandafter{\beamer@frametitle}%
  \expandafter\beamer@framesubtitletoks\expandafter{\beamer@shortframetitle}%
  \edef\beamer@callframetitle{\noexpand\frametitle[\the\beamer@framesubtitletoks]{\the\beamer@frametitletoks}}%
  \expandafter\expandafter\expandafter\beamer@autobreakframe
  \expandafter\expandafter\expandafter{%
    \expandafter\beamer@callframetitle%
    \expandafter\framesubtitle\expandafter{\insertframesubtitle}%
    \unvbox\beamer@splitbox}% NOTICE THIS LINE
}

beamer@frameslide

\newenvironment{beamer@frameslide}{%
  \ifbeamer@autobreak\else%
    \ifx\beamer@againname\@empty%
      {\let\@elt\beamer@restorecounter\beamer@overlaycounterresets}%
    \else%
      {\let\@elt\beamer@labelrestorecounter\beamer@overlaycounterresets}%
    \fi%
  \fi%
  \global\c@beamerpauses=1\relax%
  \expandafter\beamer@ifempty\expandafter{\beamer@framestartpage}{%
    \stepcounter{subsectionslide}%
    \xdef\beamer@framestartpage{\the\c@page}% only first time
  }{\clearpage\beamer@notesactions}% cleanup from previous slide
  \hypersetup{pdfpagetransition=R}%
  \hypersetup{pdfpageduration=}%
  \@ifundefined{thispdfpagelabel}{}{%
  \thispdfpagelabel{\insertframenumber}}%
  \xdef\beamer@frameendpage{\the\c@page}% every time
  \beamer@setuplinks%
  \beamer@displaybreak%
  \global\setbox\beamer@zoombox=\box\voidb@x%
  \def\beamer@zoomer{}%
  \beamer@slidehaszoomfalse%
  \gdef\insertframetitle{}%
  \gdef\insertframesubtitle{}%
  \gdef\beamer@frametitle{}%
  \gdef\beamer@shortframetitle{}%
  \gdef\beamer@framesubtitle{}%
  \let\beamer@startcomment=\beamer@startcommentinframe%
  % Start slide:
  \beamer@framenotesbegin%
    \global\setbox\beamer@framebox=\vbox\bgroup%
    \beamer@inframetrue%
    \let\frame=\framelatex% inside frames, use LaTeX's \frame command
    \begin{beamer@framepauses}%
      \refcounter{framenumber}%use frame number for  \label
      \ifbeamer@shrink%
        \hsize=\beamer@shrinkfactorinv\hsize%
        \textwidth=\beamer@shrinkfactorinv\textwidth%
        \linewidth=\beamer@shrinkfactorinv\linewidth%
      \fi%
      % Insert labels if necessary:
      \ifx\beamer@againname\@empty\else%
        \nointerlineskip\vbox to0pt{\vss%
        \label<\the\beamer@slideinframe>{\beamer@againname<\the\beamer@slideinframe>}%
        \ifnum\beamer@slideinframe=1\relax%
          \label<1>{\beamer@againname}%
        \fi%
        }\nointerlineskip%
      \fi%
      \ifx\beamer@framehypertargets\@empty\else%
        \nointerlineskip\vbox to0pt{\vss%
          \beamer@framehypertargets%
          \global\let\beamer@framehypertargets\@empty%
        }\nointerlineskip%
      \fi%
      \vskip-\parskip\vbox{}% NOTICE THIS LINE
      \ifbeamer@plainframe\nointerlineskip\fi%
    \beamer@checkframetitle}%

Before this line is the start of the frame (not slide). Notice the third line from the bottom.

After this line is the end of the frame (not slide).

    {\par
    \end{beamer@framepauses}%
  \egroup%
  \ifx\beamer@frametitle\@empty%
    \setbox\beamer@frametitlebox=\box\voidb@x%
  \else%
    \setbox\beamer@frametitlebox=\vbox{%
      \vbox{}%
      {\parskip0pt\usebeamertemplate***{frametitle}\vskip0.25em}%
    }%
  \fi%
  \ifbeamer@plainframe%
    \beamer@frametextheight=\paperheight%
  \else%
    \beamer@frametextheight=\textheight%
  \fi%
  \advance\beamer@frametextheight by-\ht\beamer@frametitlebox%
  \advance\beamer@frametextheight by-\dp\beamer@frametitlebox%
  \advance\beamer@frametextheight by-\beamer@frametopskip%
  \ifbeamer@shrink%
    \beamer@shrinkframebox%
  \fi%
  \ifx\beamer@zoomer\@empty
    \setbox\beamer@framebox=\vbox{%
      \nobreak\vbox{}\nobreak\par\nobreak\beamer@entrycode\nobreak%
      \nointerlineskip\unvbox\beamer@frametitlebox%
      \nobreak%
      \ifbeamer@autobreak%
        \vskip\beamer@frametopskipautobreak%
      \else%
        \vskip\beamer@frametopskip%
      \fi%
      \nobreak%
      \nointerlineskip\box\beamer@zoombox\nointerlineskip%
      \nobreak%
      \ifbeamer@slidehaszoom\box\beamer@framebox\else\unvbox\beamer@framebox\fi%
      % bottom skip is added in autobreakframebox
    }%
    \beamer@autobreakframebox%
  \else%
    \beamer@zoomer%
  \fi%
  \beamer@undolabels%
  \beamer@framenotesend%
  \box\beamer@framebox}
  • First of all, thanks for the effort! The question did not get a lot of attention so far. I of not understand all of it. What value should i put in my current\vspace*{\topsep} space? Amazing how you tracked down the details like \ifbeamer@slidehaszoom\box\beamer@framebox\else\unvbox\beamer@framebox\fi%. – Dr. Manuel Kuehner Mar 11 '17 at 23:13
  • 1
    @Dr.ManuelKuehner It is going to be the value of \baselineskip minus the height of the first line of the second page. But since itemize add additional vskips at the beginning of the environment, there is no guarantee this will work. You might want to try this with plane text first. – Symbol 1 Mar 11 '17 at 23:44
  • I tried \vspace*{\baselineskip} but it seems that this is not enough, so I think that \baselineskip minus something will not be an solution. I tried both, \itemize and normal text (Text\\ ). I have updated the first code example accordingly. – Dr. Manuel Kuehner Mar 12 '17 at 2:07
  • I accept your answer since it is amazingly thorough. My problem in not fully solved but at least I have more insight now. – Dr. Manuel Kuehner Mar 12 '17 at 23:54
  • 2
    Since you seem to be an expert here: any idea how to patch beamer, to e.g. not use the \vskip-\parskip\vbox{}% in the first place? I'd rather see this problem fixed in beamer itself, than trying to come up with a workaround. – Anony-Mousse May 7 '17 at 12:02

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.