Pourquoi votre PDF généré depuis HTML est cassé, et comment corriger chaque problème

Mis à jour: · Équipe Dawwerni

Visuel de titre sur la correction d'une page HTML mal rendue lors de la conversion en PDF

Quand la conversion HTML en PDF donne un mauvais rendu, la cause est presque toujours le timing ou les règles d'impression : polices et graphiques capturés avant la fin du chargement, sections 100vh à la taille de la page, en-têtes fixes répétés, fonds supprimés par le moteur d'impression ou sauts de page en plein contenu. Chaque cas se corrige en CSS ou dans les réglages du convertisseur.

D'abord, identifiez le type de PDF que vous produisez

Il existe deux façons très différentes de transformer une page web en PDF, et elles échouent différemment. Imprimer / Enregistrer en PDF utilise le moteur d'impression du navigateur : le texte reste sélectionnable, mais les règles d'impression s'appliquent, donc les fonds peuvent disparaître, les en-têtes fixes se répètent et les sauts de page tombent là où le moteur le décide. Un PDF à base de captures (une capture html2canvas ou html-to-image enregistrée avec jsPDF, comme le bouton Télécharger le PDF de notre convertisseur HTML en PDF gratuit) copie l'écran au pixel près, mais le texte n'est pas sélectionnable et les images d'autres sites peuvent manquer.

Avant de corriger quoi que ce soit, notez donc la méthode qui a produit le fichier cassé. Si le problème n'apparaît qu'avec l'une d'elles, passer à l'autre est parfois la solution la plus rapide. Le convertisseur propose les deux depuis le même aperçu, ce qui rend la comparaison immédiate. Pour le contexte, voyez les trois façons gratuites de convertir du HTML en PDF.

Tableau de dépannage : symptôme, cause et solution

SymptômeCause probableSolution
Mauvaise police (Arial, Times)Police web non chargée à la capture ou fichier inaccessibleBalise link dans le head, polices dans le zip, attendre 1-2 s
Graphiques vides ou incompletsAnimation encore en cours, canevas dimensionné pour l'écrananimation: false, attente, redimensionner au beforeprint
Le hero occupe une page entièreSections en 100vh ou h-screenheight: auto en print, ou fixer 100vh à la hauteur de fenêtre
En-tête sur chaque pageposition: fixed répété par le moteur d'impressionposition: static en print, ou en-têtes fixes affichés une fois
Fond sombre devenu blancLes navigateurs suppriment les fonds à l'impressionprint-color-adjust: exact et Graphiques d'arrière-plan
Lignes ou images coupéesUn saut de page tombe dans un élémentbreak-inside: avoid, sauts de page intelligents
Images manquantes (lazy)Images loading="lazy" jamais affichées à l'écranloading="eager", ou laisser le convertisseur faire défiler
Images manquantes seulement en PDF captureImages d'autres domaines sans en-têtes CORSUtiliser Imprimer, ou mettre les images dans le zip
Sections videsAnimations d'entrée ou au scroll qui partent d'opacity 0Figer les animations, rendre visible par défaut
Page sans styleLe CDN Tailwind Play n'a pas encore généré le CSSAttendre 2-3 secondes avant la capture

Les sections suivantes détaillent chaque solution avec du code à coller. La plupart existent aussi sous forme d'options dans l'outil HTML en PDF : vous pouvez souvent corriger le résultat sans toucher au HTML.

Polices : le PDF affiche Arial ou Times au lieu de votre police web

Les polices web se chargent après le HTML : un PDF généré trop tôt affiche la police de secours, avec d'autres retours à la ligne et d'autres largeurs. Chargez Google Fonts avec une balise link dans le head (pas un @import enfoui dans une feuille de style). Pour des polices hébergées vous-même, utilisez des chemins relatifs et convertissez un .zip contenant le HTML et les fichiers de police, pour que les chemins se résolvent.

Notre convertisseur attend les polices du document avant de capturer ; si du texte est placé par un script après le chargement, ajoutez une ou deux secondes d'attente. Prévoyez toujours une pile de secours de largeur proche pour qu'une police manquante ne casse pas la mise en page.

@font-face {
  font-family: 'Brand Sans';
  src: url('fonts/brand-sans.woff2') format('woff2');
  font-weight: 400 700;
  font-display: swap;
}
body { font-family: 'Brand Sans', system-ui, sans-serif; }

Les graphiques sont vides ou à moitié dessinés

Chart.js anime les graphiques par défaut pendant environ une seconde, et un canevas est dessiné à la taille qu'il avait à l'écran. Capturé trop tôt, le graphique a des barres absentes ou à mi-hauteur ; imprimé sur une page d'une autre largeur, le canevas peut sortir étiré. Désactivez l'animation, donnez une hauteur fixe au conteneur et redimensionnez les graphiques avant l'impression.

// The canvas sits in a container with a fixed height:
// <div style="position: relative; height: 360px"><canvas id="sales"></canvas></div>
new Chart(document.getElementById('sales'), {
  type: 'bar',
  data: {
    labels: ['Q1', 'Q2', 'Q3'],
    datasets: [{ label: 'Sales', data: [12, 19, 23] }]
  },
  options: { animation: false, responsive: true, maintainAspectRatio: false }
});

// Redraw every chart at the print size before the browser prints
window.addEventListener('beforeprint', () => {
  Object.values(Chart.instances).forEach((chart) => chart.resize());
});

Problèmes de mise en page : sections 100vh et en-têtes fixes répétés

Sections en 100vh et h-screen

Une section hero en 100vh (h-screen dans Tailwind) fait la hauteur de la fenêtre. À l'impression, les unités de viewport se calculent sur la zone de page : le hero occupe une page entière et laisse un grand vide. Dans une capture, il prend la hauteur de la fenêtre utilisée par l'outil. Réinitialisez la hauteur en print, ou laissez le convertisseur fixer les sections 100vh à la hauteur de fenêtre choisie.

@media print {
  .hero, .h-screen { min-height: auto; height: auto; padding: 48px 0; }
}

En-têtes fixes ou sticky sur chaque page

Chrome et Edge impriment les éléments en position: fixed sur chaque page : une barre de navigation fixe recouvre le haut de chaque page. Les en-têtes sticky peuvent aussi se retrouver à des endroits étranges. Passez-les en static pour l'impression et masquez les widgets inutiles sur papier. Le convertisseur peut aussi afficher les en-têtes fixes et sticky une seule fois, en haut, au lieu de les répéter.

@media print {
  header, .navbar { position: static; }
  .cookie-banner, .chat-widget, .back-to-top { display: none; }
}

Le fond sombre est devenu blanc

Pour économiser l'encre, les navigateurs suppriment couleurs et images d'arrière-plan à l'impression, sauf indication contraire. Un tableau de bord en thème sombre devient alors du texte blanc sur page blanche. Deux solutions : cocher Graphiques d'arrière-plan dans la boîte d'impression (Plus de paramètres dans Chrome et Edge), ou déclarer en CSS que les couleurs doivent être conservées. La propriété est héritée : la placer sur html couvre toute la page.

html {
  -webkit-print-color-adjust: exact; /* Safari and older Chromium */
  print-color-adjust: exact;
}

Texte, images et lignes de tableau coupés aux sauts de page

Le moteur d'impression coupe la page dès que le contenu atteint le bas de la zone imprimable, y compris au milieu d'une ligne, d'une image ou d'une carte. Indiquez-lui quels éléments doivent rester entiers, où commencer de nouvelles pages et combien de lignes peuvent rester isolées en haut ou en bas de page.

figure, img, tr, pre, blockquote, .card { break-inside: avoid; }
h2, h3 { break-after: avoid; }
.chapter { break-before: page; }
p { orphans: 3; widows: 3; }
thead { display: table-header-group; } /* repeat table headers on each page */

Images manquantes et contenu invisible

Images lazy et contenu révélé au scroll

Les images en loading="lazy" ne sont chargées qu'à l'approche du viewport, et des bibliothèques comme AOS gardent les éléments à opacity 0 tant que vous n'avez pas défilé jusqu'à eux. Une capture de toute la page peut donc montrer des cadres vides et des blocs blancs. Utilisez le chargement eager pour les images importantes, forcez l'état révélé en print, ou laissez le convertisseur faire défiler la page et forcer le chargement des images lazy avant la capture.

<img src="images/team.jpg" alt="Team photo" loading="eager" width="1200" height="800">
@media print {
  [data-aos], .reveal-on-scroll { opacity: 1 !important; transform: none !important; }
}

Images d'autres sites (CORS)

Les exports à base de captures redessinent la page sur un canevas. Les navigateurs interdisent de lire les pixels d'images d'autres domaines si ce serveur n'envoie pas d'en-têtes CORS : ces images peuvent manquer dans Télécharger le PDF, PNG ou PPTX alors qu'elles s'affichent bien avec Imprimer. Mettez les images dans un .zip à côté du HTML, hébergez-les sur un serveur qui envoie Access-Control-Allow-Origin, ou utilisez Imprimer / Enregistrer en PDF.

Animations d'entrée qui ne se terminent jamais

Si un élément est masqué dans son style de base et que seule une animation le rend visible, tout ce qui arrête l'animation (feuille de style print, capture au mauvais moment, réglage de réduction des animations) le laisse caché. Figez les animations dans leur état final dans le convertisseur, et écrivez les animations pour que l'état visible soit l'état par défaut.

/* Fragile: invisible unless the animation runs to the end */
.card { opacity: 0; animation: fade 0.5s forwards; }
@keyframes fade { to { opacity: 1; } }

/* Robust: visible by default, only the start is animated */
.card { animation: fade-in 0.5s both; }
@keyframes fade-in { from { opacity: 0; } }

Une feuille de style d'impression à coller

Ce bloc réunit les corrections ci-dessus. Ajoutez-le à la fin de votre CSS, adaptez les sélecteurs à votre page et utilisez Imprimer / Enregistrer en PDF. Attention à la dernière ligne : elle coupe les animations, elle n'est donc sûre que si vos éléments animés sont visibles par défaut, comme montré plus haut.

@page { size: A4; margin: 12mm; }

@media print {
  html { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  header, .navbar { position: static; }
  nav, .cookie-banner, .chat-widget { display: none; }
  .hero, .h-screen { min-height: auto; height: auto; }
  h2, h3 { break-after: avoid; }
  figure, img, tr, pre, .card { break-inside: avoid; }
  thead { display: table-header-group; }
  [data-aos], .reveal-on-scroll { opacity: 1 !important; transform: none !important; }
  *, *::before, *::after { animation: none !important; transition: none !important; }
}

Questions fréquentes

Pourquoi mon HTML est-il différent dans le PDF et dans le navigateur ?

Imprimer / Enregistrer en PDF applique les règles d'impression : fonds supprimés par défaut, éléments fixes répétés, sauts de page en plein contenu. Les PDF à base de captures copient l'écran mais peuvent capturer avant la fin des polices, graphiques ou animations. Identifiez la méthode, puis appliquez la solution correspondante.

Comment garder les couleurs de fond en enregistrant du HTML en PDF ?

Ajoutez print-color-adjust: exact (et sa version préfixée -webkit- pour Safari) sur l'élément html, ou cochez Graphiques d'arrière-plan dans la boîte d'impression. Les PDF à base de captures gardent les fonds automatiquement, puisqu'ils copient l'écran.

Pourquoi mes graphiques sont-ils vides dans le PDF ?

Le graphique était encore en cours d'animation, ou pas encore dessiné, au moment de la capture. Mettez animation: false dans Chart.js, attendez quelques secondes avant la capture et redimensionnez les graphiques à l'événement beforeprint pour qu'ils tiennent dans la largeur de page.

Comment empêcher un saut de page de couper une image ou une ligne de tableau ?

Appliquez break-inside: avoid aux images, figures, cartes et lignes de tableau, et display: table-header-group au thead pour répéter les en-têtes. Un élément plus haut qu'une page sera quand même coupé : gardez ces blocs plus courts qu'une page.

Pourquoi le texte de mon PDF n'est-il pas sélectionnable ?

Le PDF a été construit à partir de captures de la page (par exemple avec html2canvas et jsPDF) : chaque page est une image. Utilisez plutôt Imprimer / Enregistrer en PDF, dont le moteur d'impression conserve un vrai texte sélectionnable et consultable.

Essayez : Convertisseur HTML en PDF gratuit

Fonctionne dans votre navigateur : sans envoi, sans inscription, sans filigrane.

Un outil gratuit de Dawwerni, la fidélité gamifiée pour les commerces.