0

My goal is to have a different geometry for the first page compared to the rest of the document.

The only way I found to do this is to use the \afterpage{} command.

MWE (note the different headheights):

\documentclass[11pt, a4paper]{article}

\usepackage[left=3cm, right=3cm, top=4.1cm, bottom=3cm, headheight=1.1cm, headsep=1cm, footskip=1cm, showframe]{geometry}
\usepackage{fancyhdr}
\usepackage{kantlipsum}
\usepackage{afterpage}

\fancyhf{}
\renewcommand{\headrulewidth}{0pt}
\fancyhead{
  HEADER
}
\pagestyle{fancy}


\begin{document}
  \newgeometry{left=3cm, right=3cm, top=6.3cm, bottom=3cm, headheight=2.3cm, headsep=2cm, footskip=1cm}
  \section{Section}
  \afterpage{\clearpage\restoregeometry}
  \kant[1-10]
\end{document}
  • If \restoregeometry is called manually, everything works (except one has to place the command manually)
  • If \afterpage{Sometext} is used, "sometext" is printed onto a new page
  • If \afterpage{\restoregeometry} is used, nothing happens. E.g. \afterpage{\itshape} and \afterpage{\bfseries} don't work either
  • The order of \clearpage and \restoregeometry does not matter. \clearpage isn't necessary at all, as \restoregeometry calls \clearpage anyway (according to the geometry documentation)

What's the problem with \afterpage{}? Is there some other way to achieve the same result?

2
  • 1
    You normally never need afterpage for this. Simply use \vspace*{2cm} before the section to move it down, and let the large header stick out into the page. Jan 24 at 17:07
  • Also, the geometry of the next page is already set before \afterpage executes. \AddThispageHook might work better. OTOH, the changes might be local and not permanent. Jan 25 at 4:38
1

Now here is the solution with \afterpage. I will highlight the problems first.

As the question states, just \afterpage{\restoregeometry} doesn't work. The same applies to \afterpage{\newgeometry}. The reason is that the commands in \afterpage are executed in a local TeX group. So when \afterpage is finished, the changes are undone. They need to be applied outside of this group.

You can find a solution for this, for example in this question. They advise to use \afterpage{\aftergroup\restoregeometry}. This causes the \restoregeometry to be executed after the local group in \afterpage has finished. You must also do this for \newgeometry, but as \aftergroup only accepts a singe token, you must put the \newgeometry call in a macro. If you want the \restoregeometry to be done on the next page, you must use a nested afterpage:

\newcommand{\changegeometry}{\newgeometry{includehead,headheight=89pt}%
  \afterpage{\aftergroup\restoregeometry}%
}
\afterpage{\aftergroup\changegeometry}

However, although this works most of the time, sometimes it fails in mysterious ways. See this example:

\documentclass{article}
\usepackage{lipsum}
\usepackage{afterpage}
\usepackage[a5paper]{geometry}
\usepackage{graphicx}

\usepackage{fancyhdr}
\newcommand{\Logo}{%
    \includegraphics[height=3cm]{example-image}}
\newcommand{\cs}[1]{\texttt{\char`\\#1}}

\pagestyle{fancy}
\fancyhead[R]{\cs{textheight}=\the\textheight\ \cs{vsize}=\the\vsize}
\fancyhead[L]{}
\renewcommand{\footrulewidth}{1mm} % show where the footer is

\fancypagestyle{logo}{%
  \fancyhead[L]{\Logo}
}

\newcommand{\changegeometry}{\newgeometry{includehead,headheight=89pt}%
  \afterpage{\aftergroup\restoregeometry}%
}
\setlength\parskip{10pt plus 5pt}

\begin{document}

\afterpage{\aftergroup\changegeometry}
\afterpage{\thispagestyle{logo}}

\section{Introduction}

\lipsum[1-9]

\end{document}

Page 2 is as desired, but page 3 comes out very strange: the footer is shifted up and runs through the text.

Page 2 and 3

I have printed the value of \textheight and \vsize in the header. On page 3 \textheight is different from \vsize, while at the page level they should be the same. \vsize is the internal variable that TeX uses for page breaking; it can be different in inner boxes (like \parskip or minipage), but at the page level it should be equal to \textheight. The difference causes the weird page layout.

The reason appears to be that the lipsum package typesets its paragraph also inside a group. So ultimately, the \restoregeometry is executed inside that group, and when that group ends in the middle of page 3, the values are restored to what they were before the group. However, LaTeX's output routine makes global changes to \vsize, but not to \textheight and so they become different.

And, by the way, this would also happen if another group would cross the page boundary, such as various LaTeX environments, like itemize or center, or just \begingroup ... \endgroup. We don't even know how many group nestings there may be, so adding extra \aftergroups won't help.

The best solution would be to make the changes to \textheight, \vsize etc, global. And there are a few other internal LaTeX variables that should go with them. I wished the geometry package would do this, but unfortunately it doesn't. I can't think of a reason to keep these changes local.

So I wrote a macro to make all the changes to the page layout variables global, and call that macro after \newgeometry and \restoregeometry. And, by the way, that also makes the \aftergroup redundant.

So here is a solution that works.

\documentclass{article}
\usepackage{lipsum}
\usepackage{afterpage}
\usepackage[a5paper]{geometry}
\usepackage{graphicx}

\usepackage{fancyhdr}
\newcommand{\Logo}{%
    \includegraphics[height=3cm]{example-image}}
\newcommand{\cs}[1]{\texttt{\char`\\#1}}

\pagestyle{fancy}
\fancyhead[R]{\cs{textheight}=\the\textheight\ \cs{vsize}=\the\vsize}
\fancyhead[L]{}
\renewcommand{\footrulewidth}{1mm} % show where the footer is

\fancypagestyle{logo}{%
  \fancyhead[L]{\Logo}
}

\newcommand{\changegeometry}{\newgeometry{includehead,headheight=89pt}%
  \globalsetgeometry\afterpage{\restoregeometry\globalsetgeometry}%
}

\setlength\parskip{10pt plus 5pt}

\makeatletter
\newcommand{\globalsetgeometry}{%
  \global\textheight\textheight
  \global\@colht\textheight
  \global\@colroom\textheight
  \global\vsize\textheight
  \global\headheight\headheight
  \global\topskip\topskip
  \global\headsep\headsep
  \global\topmargin\topmargin
  \global\footskip\footskip
  %% The following are not used in most cases
  \global\textwidth\textwidth
  \global\evensidemargin\evensidemargin
  \global\oddsidemargin\oddsidemargin
  \global\baselineskip\baselineskip
  \global\marginparwidth\marginparwidth
  \global\marginparsep\marginparsep
  \global\columnsep\columnsep
  \global\hoffset\hoffset
  \global\voffset\voffset
}
\makeatother

\begin{document}

\afterpage{\changegeometry}
\afterpage{\thispagestyle{logo}}

\section{Introduction}

\lipsum[1-9]

\end{document}

Note 1. Like in my first answer, you can do this without changing the \headheight by using a \vspace, like

\afterpage{\thispagestyle{logo}\vspace*{2cm}}

Note 2. I can think of a useful application of the solution above when you want to have a sequence of pages with a different page layout, where the \afterpage{\restoregeometry\globalsetgeometry} is issued later. Otherwise you would have to issue a \vspace on each page (this can be done by a self-repeating \afterpage, however).

Note 3. I am contemplating of adding the \globalsetgeometry command to the next fancyhdr version. I am not yet sure if that is a good idea, however.

0

Edit: If it doesn't have to be in a real header, just don't use a header, put the desired text directly on the page, and shift it a bit up with `\vspace{...} before it.

I have been working on this problem this week while updating the fancyhdr documentation. Let me first say that @UlrikeFischer is absolutely right: \vspace is the best solution. However, there are some caveats that I will address in this answer.

There may also be rare cases where \afterpage with \newgeometry and \restoregeometry might be desirable. As you have noticed, this is tricky. I found all kinds of strange things with this approach, but these can be solved. I will address this in the next answer.

So let us use the simple solution. I use a5paper to keep the size manageable.

\documentclass[10pt,twoside]{article}
\usepackage{lipsum}
\usepackage[a5paper]{geometry}
\usepackage{graphicx}

\usepackage{fancyhdr}
\newcommand{\Logo}{%
    \includegraphics[height=3cm]{example-image}}

\pagestyle{fancy}
\fancyhead[R]{\thepage}
\fancyhead[L]{\leftmark}
\fancyfoot[L]{This is the footer}
\fancyfoot[C]{}

\renewcommand{\footrulewidth}{0.4pt}

\fancypagestyle{logo}{%
  \fancyhead[L]{\Logo}
}

\begin{document}

% This will cause a warning about \headheight too small.
% And on older versions of fancyhdr this will destroy the layout
% of the following pages.

\thispagestyle{logo}\vspace*{2cm}

\section{Introduction}

\lipsum

\end{document}

This will give the desired layout:

enter image description here

However, fancyhdr will also give a warning:

Package fancyhdr Warning: \headheight is too small (12.0pt): 
(fancyhdr)                Make it at least 88.9583pt, for example:
(fancyhdr)                \setlength{\headheight}{88.9583pt}.
(fancyhdr)                You might also make \topmargin smaller to compensate:
(fancyhdr)                \addtolength{\topmargin}{-76.9583pt}.

What's even worse, on older versions of fancyhdr (version 3.x) it will also make the header taller on all following pages, thereby shifting down the text body. That is definitely not what you want. With fancyhdr version 4.x you could just ignore this warning, but there are nicer solutions.

  1. With fancyhdr version 4.x you can use the nocheck option:
\usepackage[nocheck]{fancyhdr}

This eliminates the warning, and with version 4.x the following pages are also not affected. But this eliminates all checks on the headers and footers, so this could hide some problems. In the next fancyhdr release I will add a command to eliminate the check for a specific pagestyle. And if you are still stuck with fancyhdr version 3.x this will not help.

  1. Put the big part of the header (the Logo) in a zero-height box.
    \fancyhead[L]{\raisebox{-2.7cm}[0pt][0pt]{\Logo}}

(This solution was given by @UlrikeFischer.)

The first parameter of \raisebox can be used to shift the Logo up or down. However, the rule under the header will now cross through the logo which I am sure is not what you want.

enter image description here

You could just remove the rule, for example with \renewcommand{\headrule}{} inside the logo page style. Or you do the rule yourself, see below.

  1. If we want to add a rule ourselves, \raisebox will not suffice, because we will have to use a vertical layout. But for this a \parbox can be used, where we specify that it should have a 0 height, so it doesn't generate warnings, and doesn't really take excessive space in the header:
\fancypagestyle{logo}{%
  \fancyhead[L]{%
    \parbox[t][0pt]{\textwidth}{
      \vspace{-1ex}
      \Logo\\[-0.7\baselineskip]\rule{\textwidth}{\headrulewidth}}}
  \renewcommand{\headrule}{}
}

The first \vspace{-1ex} in the \parbox is necessary, because the real height of the \parbox will not be 0pt, but the heigt of the first 'line' of its contents. Without the vspace this would be the logo, so it wouldn't work. We have to put some empty 'line' there, and to compensate it with a negative vertical space.

This gives essentially the same visual output as our original solution, but without fancyhdr warnings, and also applicable to fancyhdr version 3.x. You may have to fiddle a bit with the vertical spaces.

  1. An alternative to forcing the height of the \parbox is to end it with negative vertical space \vspace{-3cm} to compensate for its contents. This may actually be simpler:
\fancypagestyle{logo}{
  \fancyhead[L]{
    \Logo\\[-0.7\baselineskip]\rule{\textwidth}{\headrulewidth}
    \vspace{-3cm}}
  \renewcommand{\headrule}{}
}

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.