Pourquoi votre PDF généré depuis HTML est cassé, et comment corriger chaque problème
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ôme | Cause probable | Solution |
|---|---|---|
| Mauvaise police (Arial, Times) | Police web non chargée à la capture ou fichier inaccessible | Balise link dans le head, polices dans le zip, attendre 1-2 s |
| Graphiques vides ou incomplets | Animation encore en cours, canevas dimensionné pour l'écran | animation: false, attente, redimensionner au beforeprint |
| Le hero occupe une page entière | Sections en 100vh ou h-screen | height: auto en print, ou fixer 100vh à la hauteur de fenêtre |
| En-tête sur chaque page | position: fixed répété par le moteur d'impression | position: static en print, ou en-têtes fixes affichés une fois |
| Fond sombre devenu blanc | Les navigateurs suppriment les fonds à l'impression | print-color-adjust: exact et Graphiques d'arrière-plan |
| Lignes ou images coupées | Un saut de page tombe dans un élément | break-inside: avoid, sauts de page intelligents |
| Images manquantes (lazy) | Images loading="lazy" jamais affichées à l'écran | loading="eager", ou laisser le convertisseur faire défiler |
| Images manquantes seulement en PDF capture | Images d'autres domaines sans en-têtes CORS | Utiliser Imprimer, ou mettre les images dans le zip |
| Sections vides | Animations d'entrée ou au scroll qui partent d'opacity 0 | Figer les animations, rendre visible par défaut |
| Page sans style | Le CDN Tailwind Play n'a pas encore généré le CSS | Attendre 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());
});- Dans le convertisseur, ajoutez quelques secondes d'attente pour les pages qui construisent leurs graphiques par script.
- Les transitions D3 se comportent comme des animations : capturez après leur fin, ou sautez la transition à l'impression.
- Les graphiques dessinés en WebGL peuvent sortir vides dans les exports à base de captures.
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 */- break-inside: avoid est bien pris en charge ; il ne peut rien pour un élément plus haut qu'une page, qui sera quand même coupé.
- Les sauts dans les conteneurs flex et grid sont gérés de façon moins homogène que dans un flux de blocs classique ; gardez les cartes imprimables dans un flux simple quand c'est possible.
- orphans et widows fonctionnent dans Chromium et Safari, mais pas dans Firefox.
- break-after: avoid sur les titres est moins bien pris en charge que break-inside : testez dans le navigateur avec lequel vous imprimez.
- Le Télécharger le PDF à base de captures de notre convertisseur place des sauts intelligents qui évitent de couper paragraphes, images et lignes de tableau quand c'est possible.
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; }
}- Pages générées par IA ? Le guide ChatGPT canvas vers PDF propose un prompt pour demander à l'IA d'ajouter le CSS d'impression.
- Vous faites des slides plutôt que des documents ? Suivez les règles pour des slides HTML qui survivent à la conversion.
- Pour comparer les méthodes et les réglages de base, revenez au guide de conversion HTML en PDF gratuite.
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.