Comment modifier des marges en cours de document ?#

Il faut distinguer plusieurs opérations :

Pour toutes ces opérations, on peut généralement utiliser soit des commandes de base, soit l’extension changepage.

Avertissement

Il existe aussi une extension chngpage, à la syntaxe un peu différente, qui est classée comme obsolète. L’une des raisons est que, contrairement à changepage, elle ne prend pas en charge la classe memoir.

1.  Modification de la largeur d’un paragraphe ou d’un groupe de paragraphes#

1.1.  Avec des commandes de base de #

La solution la plus simple reste d’utiliser les dimensions de \leftskip et \rightskip, qui définissent l’espacement supplémentaire à gauche et à droite du paragraphe.

\documentclass{article}
\usepackage{lipsum}

\newenvironment{retrecir}[2]{
  \begingroup
  \leftskip=\dimexpr\leftskip#1\relax
  \rightskip=\dimexpr\rightskip#2\relax
  }
  {\endgroup}

\begin{document}

\lipsum[1]

\begin{retrecir}{+2cm}{+1cm}

  \lipsum[2]
  
\end{retrecir}

\lipsum[3]

\end{document}

Bien sûr, on peut élargir le paragraphe en donnant des arguments négatifs.

1.2.  Avec des commandes de base de #

Pour ajuster la largeur du texte en cours de document, la méthode suivante passe par un environnement changemargin dont les arguments indiquent la modification à effectuer sur les marges de gauche et de droite respectivement. Voici sa définition avec un exemple d’utilisation :

\documentclass{article}
\usepackage{lipsum}

\newenvironment{changemargin}[2]{%
  \begin{list}{}{%
    \setlength{\topsep}{0pt}%
    \setlength{\leftmargin}{#1}%
    \setlength{\rightmargin}{#2}%
    \setlength{\listparindent}{\parindent}%
    \setlength{\itemindent}{\parindent}%
    \setlength{\parsep}{\parskip}%
  }%
  \item[]}
  {\end{list}}

\begin{document}

\lipsum[1]

\begin{changemargin}{-1cm}{-1cm}

  \lipsum[2]
  
\end{changemargin}

\end{document}

Cet environnement (qui est proche de l’environnement quote) ne change pas la largeur du texte à l’échelle du document, c’est-à-dire \hsize ou \textwidth, mais il insère son texte dans un environnement list, qui lui-même utilise \parshape, une primitive de qui permet de composer un paragraphe de n’importe quelle forme. J’ignore pourquoi la FAQ anglophone recommande une solution aussi contournée alors qu’il est très simple d’ajuster \leftskip et \rightskip.

1.3.  Avec l’extension changepage#

L’extension changepage fournit un environnement adjustwidth qui est équivalent à l’environnement changemargin défini ci-dessus.

2.  Modification de la longueur de la page, donc du nombre de lignes#

2.1.  Avec des commandes de base#

Changer les dimensions verticales d’une page est assez simple : la commande \enlargethispage ajuste la taille de la page courante en fonction de son argument. Voici un exemple courant augmentant la longueur de la page de la hauteur d’un ligne de texte :

\enlargethispage{\baselineskip}

Et voici l’opération opposée, réduisant la longueur de la page de la hauteur d’un ligne de texte :

\enlargethispage{-\baselineskip}

2.2.  Avec l’extension addlines#

Le processus est (dans une certaine mesure) simplifié par l’extension addlines. Sa commande \addlines prend comme argument le nombre de lignes à ajouter à la page (plutôt qu’une longueur) : la documentation de l’extension présente une analyse du moment où la commande peut fonctionner ou pas.

3.  Changement de la mise en page du document avec effet immédiat au milieu de la page#

changepage fournit deux commandes qui modifient la mise en page à la volée. Elles peuvent toutes deux être utilisées en plein milieu d’une page. Dans ces deux commandes, les arguments indiquent non pas des valeurs absolues, mais les modifications à apporter (donc 2cm est équivalent à +2cm) :

  • \changetext{<hauteur>}{<largeur>}{<marge extérieure>}{<marge intérieure>}{<séparation de colonnes>} : Cette commande modifie les marges pour l’ensemble de la page courante, mais elle modifie la largeur du texte uniquement à partir de l’endroit où elle est invoquée.

  • \changepage prend les mêmes arguments que \changetext avec les mêmes effets, mais ajoute en outre {<marge supérieure>}{<hauteur de l'en-tête>}{<espace sous l'en-tête>}{<espace au-dessus du pied de page>}.

Attention : les paragraphes qui suivent cette commande seront alignés à gauche au même niveau que les paragraphes qui précèdent : le paramètre <largeur> affecte uniquement l’alignement à droite ! Si vous souhaitez que l’alignement à gauche soit décalé (comme dans l’environnement quote), utilisez l’environnement adjustwidth présenté plus haut ou, si vous souhaitez que le changement soit définitif ou sur plusieurs pages, ajustez \leftskip et \rightskip.

4.  Changement programmé de la mise en page d’une page à l’autre#

La technique exposée ci-dessous s’applique particulièrement à un cas (même si on peut en imaginer d’autres!) : lorsque l’on imprime un gros livre en dos carré collé, la marge intérieure des pages centrales disparaît en partie dans la reliure, si bien que, dans les cas extrêmes, une partie du texte peut disparaître. L’idéal serait donc de décaler progressivement la zone de texte vers la droite à mesure que l’on se rapproche du milieu du livre afin de conserver une marge intérieure satisfaisante. Pour que cette modification reste insensible, il faut qu’elle se fasse petit à petit, sur l’ensemble des pages.

Pour cela, on peut modifier l’output routine, c’est-à-dire l’ensemble de macros qui détermine comment la page est composée, notamment l’emplacement de la zone de texte principale et des paratextes.

Le document minimal suivant montre comment s’y prendre. Deux remarques sur cet exemple :

  • Pour les besoins de la démonstration, le décalage est largement exagéré : en réalité, il faut le calculer en fonction du nombre de pages, de l’épaisseur du papier et de sa rigidité. Normalement, il est de l’ordre de la fraction de millimètre ;

  • Cette technique fonctionne aussi avec l’option twoside. Elle est omise ici pour que l’on voie mieux le décalage d’une page à l’autre.

\documentclass[11pt,latin]{article}
\usepackage[a5paper]{geometry}

\usepackage{babel}
\usepackage{lipsum}
\usepackage{ifthen}

\newlength\offset
\setlength\offset{5mm} % À ajuster.

\newcommand*\adjustmargins{
  % Cette macro décale la zone de texte vers l'extérieur
  % à mesure que l'on s'approche du milieu du livre,
  % puis la décale à nouveau vers l'intérieur
  % une fois que l'on a dépassé le milieu.
  \ifthenelse{\thepage<\numexpr\PreviousTotalPages/2}{
    \global\addtolength\oddsidemargin\offset
    \global\addtolength\evensidemargin{-\offset}
  }{
    \global\addtolength\oddsidemargin{-\offset}
    \global\addtolength\evensidemargin\offset
  }
  % À ajouter si l'on utilise la classe memoir.
  % \global\spinemargin=\oddsidemargin\relax
  % \global\foremargin=\evensidemargin\relax
}

% On exécute ces modifications une fois que TeX a composé la page.
% Les valeurs modifiées seront donc utilisées pour la page suivante.
\AddToHook{shipout/after}\adjustmargins

\begin{document}

\lipsum[1-20]

% Le nombre total de pages n'est connu
% qu'à partir de la deuxième compilation :
% la ligne suivante sert uniquement à éviter
% que le document ne soit compilé qu'une fois.
\label{dummy}

\end{document}

Si l’on a une version ancienne de qui ne fournit pas \AddToHook, on peut remplacer la ligne correspondante par \AtBeginShipout\adjustmargins, ce qui suppose de charger l’extension atbegshi. Le décalage sera opéré dès la première page en procédant ainsi, mais comme il est infime, les conséquences n’en seront pas perceptibles.

De même, si la macro \PreviousTotalPages n’est pas définie, le plus simple est encore de renseigner manuellement le nombre de pages de votre document.

Attention

Les extensions lastpage, totpages et count1to ne permettent pas d’obtenir le nombre de pages total sous la forme d’une valeur brute, ce qui est nécessaire pour opérer la division par deux dans \ifthenelse. Si vous tenez à automatiser le calcul tout en conservant une version de qui ne fournit pas \PreviousTotalPages, il faudra utiliser zref (en particulier \zref@extract) avec abspage.


Sources