PDFMove
Comment fonctionne la logique CSS print dans la conversion HTML vers PDF ?
Guide

Comment fonctionne la logique CSS print dans la conversion HTML vers PDF ?

9 min de lecture

Lorsque vous convertissez une page web en PDF, vous obtenez un résultat différent de ce que vous voyez à l'écran — et ce n'est pas un bug, c'est la conséquence naturelle du passage entre deux modèles de mise en page. Dans cet article, nous expliquons comment les pages web sont découpées en pages, quelles sont les règles d'impression de CSS et pourquoi le contenu dynamique pose problème.

Deux modèles de mise en page

Une page web est un support continu. La notion de page n'y existe pas ; le contenu s'écoule de haut en bas dans une colonne infinie. La largeur varie selon la fenêtre du navigateur et la mise en page s'y adapte.

Le PDF est un support paginé. Il comporte des pages de dimensions fixes et le contenu y est réparti.

CSS distingue les deux par la notion de « type de média » et permet d'appliquer des règles différentes.

@media print : deux jeux de styles distincts

Les pages web peuvent définir des styles différents pour l'écran et pour l'impression :

/* Pour tout le monde */
body { font-family: sans-serif; }

/* Uniquement à l'écran */
@media screen {
  nav { position: fixed; background: #222; }
}

/* Uniquement à l'impression */
@media print {
  nav, .sidebar, .publicite, .commentaires { display: none; }
  body { font-size: 11pt; color: #000; background: #fff; }
  a { text-decoration: underline; }
}

La production du PDF utilise les règles print. Sur les sites bien conçus, cela nettoie nettement la sortie :

  • Les menus de navigation, les barres latérales et les publicités sont masqués.
  • Les couleurs deviennent simples et lisibles.
  • Les tailles de texte sont exprimées en points.

Mais cela engendre aussi deux types de problèmes :

Un masquage excessif. Certains sites masquent dans leur feuille d'impression des encadrés porteurs d'information importante.

L'absence totale de styles. Les sites qui n'ont pas défini de styles d'impression utilisent la mise en page écran telle quelle, et le résultat est généralement mauvais — les menus en position fixe peuvent se répéter sur chaque page, les fonds sombres peuvent poser problème.

L'équivalence physique des unités CSS

Dans le contexte de l'impression, les unités CSS ont des valeurs physiques précises :

| Unité | Équivalent physique | |---|---| | 1in (pouce) | 2,54 cm | | 1cm | 1 cm | | 1mm | 1 mm | | 1pt (point) | 1/72 de pouce | | 1pc (pica) | 12 points | | 1px (pixel CSS) | 1/96 de pouce |

La dernière ligne est déterminante : 96 pixels CSS font exactement 1 pouce.

Conséquence de cette constante : une page A4 (210 mm = 8,27 pouces de large) fait environ 794 pixels CSS de large, marges non déduites.

Et cela produit un effet important sur les designs responsives. De nombreux sites utilisent des points de rupture de ce type :

@media (max-width: 768px) { /* mise en page tablette et mobile */ }
@media (max-width: 1024px) { /* mise en page petit écran */ }

794 pixels se situe sous la seconde règle, et sur certains sites, proche de la première. Résultat : dans le PDF, la page bascule vers une mise en page différente de celle que vous voyez sur ordinateur — les colonnes s'empilent, le menu se réduit à une icône hamburger, les images prennent toute la largeur.

C'est la réponse à la question « pourquoi la page ressemble-t-elle à une version mobile dans le PDF ? ».

Les pistes de solution : utiliser l'orientation paysage (~1123 pixels pour un A4 en paysage), réduire les marges ou appliquer une mise à l'échelle.

@page : définir la page elle-même

En CSS, la règle @page définit la boîte de page :

@page {
  size: A4;
  margin: 2cm 1.5cm;
}

Pour size, on peut utiliser des formats prédéfinis (A4, A3, Letter, Legal) ou des dimensions personnalisées (size: 210mm 297mm). Le mot-clé landscape change l'orientation.

Les pseudo-classes permettent d'appliquer des règles différentes selon les pages :

@page :first {
  margin-top: 5cm;   /* espace en haut de la page de couverture */
}

@page :left {
  margin-left: 3cm;  /* marge de reliure */
}

@page :right {
  margin-right: 3cm;
}

On s'en sert pour ménager une marge de reliure dans les sorties recto-verso de type livre.

L'algorithme de saut de page

Le flux de contenu est découpé en tranches de la hauteur d'une page. Lorsque le point de coupe tombe au milieu d'un élément, le navigateur doit trancher.

CSS propose des propriétés qui orientent cette décision :

/* Que cet élément ne soit pas coupé en deux */
table, figure, .carte { page-break-inside: avoid; }

/* Qu'une nouvelle page commence avant cet élément */
h1, .chapitre { page-break-before: always; }

/* Qu'il n'y ait pas de coupure juste après cet élément */
h2, h3 { page-break-after: avoid; }

La troisième règle est particulièrement utile : elle évite qu'un titre reste seul en bas de page (avec le texte qui le suit sur la page d'après).

Contrôle des lignes orphelines et veuves :

p {
  orphans: 3;  /* au moins 3 lignes d'un paragraphe en bas de page */
  widows: 3;   /* au moins 3 lignes en haut de page */
}

Ce sont des règles typographiques classiques : une ligne isolée d'un paragraphe en fin ou en début de page fait mauvais effet.

Comportement de coupure selon le type d'élément :

| Élément | Comportement de coupure | |---|---| | Bloc de texte | Coupé aux limites de ligne | | Tableau | Coupé aux limites de rangée | | Image | Non sécable ; elle bascule ou se retrouve tronquée | | Élément positionné | Résultats imprévisibles | | Flexbox / Grid | Prise en charge variable selon le navigateur |

Les deux dernières lignes sont importantes : le positionnement absolu et les systèmes de mise en page modernes ne se comportent pas toujours bien à l'impression. Une grille complexe peut se disloquer de façon inattendue à la limite d'une page.

Pourquoi les fonds ne s'impriment-ils pas

Les moteurs d'impression n'impriment pas par défaut les couleurs et images d'arrière-plan. C'est un comportement intégré, destiné à économiser l'encre.

Il existe un moyen de le forcer en CSS :

* {
  -webkit-print-color-adjust: exact;
  print-color-adjust: exact;
}

La boîte de dialogue d'impression du navigateur comporte également une option « Graphiques d'arrière-plan ».

Lorsque ce réglage est désactivé, les designs à fond sombre tournent à la catastrophe : du texte blanc sur fond noir devient blanc sur blanc dès que le fond n'est pas imprimé, et plus rien n'est visible.

Si vous préparez vous-même votre HTML, inverser les couleurs dans la feuille d'impression est une approche plus sûre :

@media print {
  .section-sombre { background: #fff; color: #000; }
}

Liens et interactivité

Les hyperliens sont généralement convertis en annotations de lien PDF et restent cliquables. Cela dépend des capacités du convertisseur.

Dans un document imprimé, la destination d'un lien reste invisible. Il est possible d'ajouter l'adresse au texte via CSS :

@media print {
  a[href^="http"]::after {
    content: " (" attr(href) ")";
    font-size: 0.8em;
    color: #555;
  }
}

Les champs de formulaire sont généralement réduits à leur apparence statique. Certains convertisseurs savent transformer les formulaires HTML en champs de formulaire PDF, mais ce n'est pas une fonctionnalité répandue.

Les interactions JavaScript disparaissent complètement : menus déroulants, onglets, accordéons. Le contenu à l'état replié n'apparaît pas du tout dans le PDF — si une section de questions fréquentes est présentée en accordéon, seules les questions apparaîtront dans le PDF, pas les réponses.

Dans ce cas, il faut déplier les contenus masqués dans la feuille d'impression :

@media print {
  .contenu-accordeon { display: block !important; }
}

Contenu dynamique et problème de temporisation

La plupart des pages web modernes récupèrent leur contenu après le chargement de la page : appels d'API, images en chargement différé, défilement infini.

Le convertisseur considère la page comme « prête » à un moment donné et lance la production du PDF. Différentes stratégies servent à déterminer ce moment :

  • L'événement de chargement (load) : quand les premières ressources de la page sont arrivées. Généralement insuffisant.
  • Le réseau au repos (network idle) : quand aucune nouvelle requête n'a été émise pendant un certain temps. Un meilleur signal.
  • L'attente fixe : attendre 3 secondes, par exemple. Grossier mais simple.
  • L'attente d'un élément : attendre qu'un sélecteur CSS donné apparaisse. La méthode la plus fiable, mais elle demande une configuration.

Sur les pages à défilement infini, aucune stratégie ne peut restituer l'intégralité du contenu — celui-ci ne se charge qu'au fur et à mesure que l'utilisateur fait défiler, et le convertisseur ne fait pas défiler.

Les images en chargement différé (lazy loading) posent le même problème : les images qui n'entrent pas dans la zone d'affichage ne se chargent jamais et restent vides dans le PDF.

Chargement des polices

Les polices web sont téléchargées depuis des sources externes :

@font-face {
  font-family: 'Speciale';
  src: url('https://fonts.example.com/speciale.woff2');
}

Si l'environnement de conversion ne peut pas atteindre cette ressource, la police n'est pas chargée et le navigateur se rabat sur une police de substitution. Les chasses de caractères changeant, la mise en page se décale.

Il y a en outre un problème de temporisation : si le PDF est produit avant le chargement de la police, la page est dessinée avec la police de substitution.

Pour les documents critiques, les solutions sont :

  • Intégrer la police en base64 dans le CSS.
  • Utiliser des polices système.
  • Ajouter un contrôle qui attend le chargement des polices.

En résumé

La conversion de HTML en PDF est un passage d'un support continu à un support paginé, et CSS gère cette transition via @media print, @page et les propriétés de saut de page. Comme le pixel CSS est défini à 1/96 de pouce, une page A4 fait environ 794 pixels de large, ce qui fait basculer les designs responsives en mise en page mobile. Les fonds ne s'impriment pas par défaut, ce qui pose un vrai problème sur les designs à fond sombre. Les décisions de saut de page peuvent être orientées par des propriétés comme page-break-inside, orphans et widows, mais ces règles doivent être définies dans le code de la page elle-même. Enfin, le contenu dynamique peut arriver incomplet selon le moment où le convertisseur décide que la page est « prête » — sur les pages à défilement infini et à chargement différé, obtenir le contenu intégral est généralement impossible.

Questions fréquentes

À quelle mesure physique correspond un pixel en CSS ?

Dans le contexte de l'impression, le pixel CSS est défini comme 1/96 de pouce. Autrement dit, 96 pixels font exactement 1 pouce, soit environ 2,54 centimètres. Grâce à cette constante, une page A4 (210 mm de large) fait environ 794 pixels CSS de large. C'est la raison pour laquelle les designs responsives basculent en mise en page mobile dans le PDF — 794 pixels se situe en dessous du point de rupture tablette ou mobile de nombreux sites.

Que fait la règle @page ?

Elle définit la page elle-même : dimensions, orientation et marges. Par exemple, la règle @page { size: A4 landscape; margin: 1.5cm; } produit une sortie A4 en paysage avec 1,5 cm de marge sur chaque bord. Les pseudo-classes :first, :left et :right permettent en outre d'appliquer des règles distinctes à la première page ou aux pages paires et impaires.

Comment l'algorithme de saut de page prend-il sa décision ?

Le flux de contenu est découpé en tranches de la hauteur d'une page. Si le point de coupe tombe au milieu d'un élément, le navigateur consulte d'abord les propriétés de saut de page (comme page-break-inside) ; en l'absence de contrainte, il coupe l'élément en deux. Les blocs de texte se coupent aux limites de ligne, les tableaux aux limites de rangée, et les images, ne pouvant pas être coupées, basculent entièrement sur la page suivante ou se retrouvent tronquées.

Pourquoi le contenu généré en JavaScript n'arrive-t-il parfois pas dans le PDF ?

Parce que le convertisseur considère la page comme « prête » à un moment donné et lance la production du PDF. Si le contenu arrive après le chargement de la page via des requêtes réseau distinctes et que le convertisseur n'attend pas assez longtemps, la sortie est produite avant que ces requêtes soient terminées. Certains outils attendent l'arrêt du trafic réseau, mais sur les pages à défilement infini ou à rafraîchissement périodique, cet arrêt ne survient jamais.

Essayez dès maintenant avec HTML/URL → PDF.

Essayer HTML/URL → PDF