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}
allowframebreaks
just shouldn't be used.allowframebreaks
because this option isn't at all intended for use with content you are actually going to present on screen.The use of this option is \emph{evil}.
(page 60)