لماذا يبدو ملف PDF المحوَّل من HTML معطوباً، وكيف تصلح كل مشكلة؟
عندما لا يظهر تحويل HTML إلى PDF بشكل صحيح، يكون السبب غالباً التوقيت أو قواعد الطباعة: خطوط ورسوم بيانية التُقطت قبل اكتمال تحميلها، أو أقسام 100vh بحجم الصفحة، أو رؤوس ثابتة مكرّرة، أو خلفيات حذفها محرّك الطباعة، أو فواصل صفحات تقطع المحتوى. ولكل مشكلة حلّ مباشر في CSS أو في إعدادات المحوّل.
أولاً: حدّد نوع ملف PDF الذي تنتجه
هناك طريقتان مختلفتان تماماً لتحويل صفحة ويب إلى PDF، ولكل منهما أعطالها. خيار الطباعة / الحفظ بصيغة PDF يستخدم محرّك الطباعة في المتصفح: يبقى النص قابلاً للتحديد، لكن قواعد الطباعة تُطبَّق، فقد تختفي الخلفيات وتتكرّر الرؤوس الثابتة وتقع فواصل الصفحات حيث يقرّر المحرّك. أما ملف PDF المبني على لقطات الشاشة (لقطة بمكتبة مثل html2canvas أو html-to-image تُحفظ عبر jsPDF، مثل زر تنزيل PDF في محوّلنا المجاني من HTML إلى PDF) فينسخ الشاشة بكسلاً بكسلاً، لكن النص غير قابل للتحديد وقد تغيب الصور القادمة من مواقع أخرى.
لذا قبل أي إصلاح، لاحظ الطريقة التي أنتجت الملف المعطوب. إذا ظهرت المشكلة في إحداهما فقط، فالانتقال إلى الأخرى أحياناً هو أسرع حلّ. ويتيح المحوّل الطريقتين من المعاينة نفسها، فتصبح المقارنة سريعة. وللاطلاع على الخلفية، راجع الطرق المجانية الثلاث لتحويل HTML إلى PDF.
جدول استكشاف الأخطاء: العَرَض والسبب والحل
| العَرَض | السبب المحتمل | الحل |
|---|---|---|
| خط خاطئ (Arial أو Times) | خط الويب لم يُحمَّل لحظة الالتقاط أو ملفه غير متاح | وسم link في head، ملفات الخطوط داخل zip، انتظار 1-2 ثانية |
| رسوم بيانية فارغة أو ناقصة | الحركة ما زالت جارية، اللوحة بمقاس الشاشة | animation: false، انتظار إضافي، إعادة الحجم عند beforeprint |
| القسم الرئيسي يملأ صفحة كاملة | أقسام 100vh أو h-screen | height: auto عند الطباعة، أو تثبيت 100vh على ارتفاع النافذة |
| الترويسة في كل صفحة | محرّك الطباعة يكرّر position: fixed | position: static عند الطباعة، أو إظهار الرؤوس الثابتة مرة واحدة |
| الخلفية الداكنة صارت بيضاء | المتصفحات تحذف الخلفيات عند الطباعة | print-color-adjust: exact وخيار رسومات الخلفية |
| أسطر أو صور مقطوعة | فاصل الصفحة يقع داخل عنصر | break-inside: avoid وفواصل صفحات ذكية |
| صور مفقودة (lazy) | صور loading="lazy" لم تظهر في الشاشة قط | loading="eager"، أو ترك المحوّل يمرّر الصفحة |
| صور مفقودة في PDF اللقطات فقط | صور من نطاقات أخرى دون ترويسات CORS | استخدام الطباعة، أو وضع الصور داخل zip |
| أقسام فارغة | حركات ظهور أو تمرير تبدأ من opacity 0 | تجميد الحركات، وجعل الظهور هو النمط الافتراضي |
| صفحة بلا تنسيق | Tailwind Play CDN لم يولّد CSS بعد | الانتظار 2-3 ثوانٍ قبل الالتقاط |
تشرح الأقسام التالية كل حلّ مع شيفرة جاهزة للّصق. ومعظم هذه الحلول متاحة أيضاً كخيارات في أداة تحويل HTML إلى PDF، فيمكنك غالباً إصلاح النتيجة دون لمس ملف HTML.
الخطوط: ملف PDF يستخدم Arial أو Times بدلاً من خط الويب
تُحمَّل خطوط الويب بعد ملف HTML، فيظهر الخط البديل في ملف PDF المُنشأ مبكراً، مع انكسار أسطر وعروض مختلفة. حمّل Google Fonts بوسم link داخل head (لا بأمر @import مدفون في ملف أنماط). وللخطوط المستضافة لديك، استخدم مسارات نسبية وحوّل ملف .zip يضمّ ملف HTML وملفات الخطوط حتى تُحلّ المسارات.
ينتظر محوّلنا خطوط المستند قبل الالتقاط؛ وإذا كان النص يُضاف بسكربت بعد التحميل، فأضف ثانية أو ثانيتين من الانتظار. واحرص دائماً على خطوط بديلة قريبة في العرض حتى لا يكسر خطٌ مفقود التخطيط.
@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; }
الرسوم البيانية فارغة أو مرسومة جزئياً
تحرّك مكتبة Chart.js الرسوم افتراضياً لمدة ثانية تقريباً، وتُرسم اللوحة بالمقاس الذي كانت عليه في الشاشة. فإذا التُقطت مبكراً ظهرت الأعمدة ناقصة أو بنصف ارتفاعها، وإذا طُبعت على صفحة بعرض مختلف قد تخرج اللوحة ممطوطة. عطّل الحركة، وامنح حاوية الرسم ارتفاعاً ثابتاً، وأعد تحجيم الرسوم قبل الطباعة.
// 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());
});- في المحوّل، أضف بضع ثوانٍ من الانتظار للصفحات التي تبني رسومها بالسكربتات.
- انتقالات D3 تتصرّف كالحركات: التقط الصفحة بعد انتهائها، أو تخطَّ الانتقال عند الطباعة.
- الرسوم المرسومة بتقنية WebGL قد تظهر فارغة في المخرجات المبنية على اللقطات.
مشاكل التخطيط: أقسام 100vh والرؤوس الثابتة المكرّرة
أقسام 100vh وh-screen
القسم الرئيسي المضبوط على 100vh (أو h-screen في Tailwind) يكون بارتفاع النافذة. وعند الطباعة تُحسب وحدات نافذة العرض على مساحة الصفحة، فيحتلّ القسم صفحة كاملة ويترك فراغاً كبيراً. وفي الالتقاط بالصور يأخذ ارتفاع النافذة التي تستخدمها الأداة. أعد ضبط الارتفاع عند الطباعة، أو دع المحوّل يثبّت أقسام 100vh على ارتفاع النافذة الذي اخترته.
@media print {
.hero, .h-screen { min-height: auto; height: auto; padding: 48px 0; }
}رؤوس ثابتة أو لاصقة في كل صفحة
يطبع Chrome وEdge العناصر ذات position: fixed في كل صفحة، فيغطّي شريط التنقّل الثابت أعلى كل صفحة. وقد تظهر الرؤوس اللاصقة (sticky) في أماكن غريبة أيضاً. اجعلها static عند الطباعة وأخفِ العناصر التي لا معنى لها على الورق. ويمكن للمحوّل أيضاً إظهار الرؤوس الثابتة واللاصقة مرة واحدة في الأعلى بدلاً من تكرارها.
@media print {
header, .navbar { position: static; }
.cookie-banner, .chat-widget, .back-to-top { display: none; }
}
الخلفية الداكنة صارت بيضاء
توفيراً للحبر، تحذف المتصفحات ألوان الخلفية وصورها عند الطباعة ما لم يُطلب غير ذلك. فتتحوّل لوحة تحكّم داكنة إلى نص أبيض على صفحة بيضاء. هناك حلّان: تفعيل خيار رسومات الخلفية في نافذة الطباعة (ضمن المزيد من الإعدادات في Chrome وEdge)، أو التصريح في CSS بوجوب الحفاظ على الألوان كما هي. والخاصية موروثة، فوضعها على html يشمل الصفحة كلها.
html {
-webkit-print-color-adjust: exact; /* Safari and older Chromium */
print-color-adjust: exact;
}
نصوص وصور وصفوف جداول مقطوعة عند فواصل الصفحات
يقطع محرّك الطباعة الصفحة حيثما يصل المحتوى إلى أسفل المساحة القابلة للطباعة، حتى لو كان ذلك في منتصف سطر أو صورة أو بطاقة. أخبره بالعناصر التي يجب أن تبقى كاملة، وأين تبدأ صفحات جديدة، وكم سطراً يمكن أن يبقى منفرداً في أعلى الصفحة أو أسفلها.
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 مدعومة جيداً، لكنها لا تفيد مع عنصر أطول من صفحة، إذ سيُقسَم رغم ذلك.
- الفواصل داخل حاويات flex وgrid تُعالَج بشكل أقل اتساقاً من التخطيط الكتلي العادي؛ أبقِ البطاقات القابلة للطباعة في تدفّق بسيط قدر الإمكان.
- تعمل orphans وwidows في Chromium وSafari لكن لا تعمل في Firefox.
- دعم break-after: avoid على العناوين أقل اتساقاً من break-inside، فاختبره في المتصفح الذي تطبع منه.
- زر تنزيل PDF المبني على اللقطات في محوّلنا يضع فواصل ذكية تتجنّب قطع الفقرات والصور وصفوف الجداول قدر الإمكان.
صور مفقودة ومحتوى غير مرئي
الصور الكسولة والمحتوى الذي يظهر بالتمرير
الصور ذات loading="lazy" لا تُجلب إلا عند اقترابها من نافذة العرض، ومكتبات مثل AOS تُبقي العناصر عند opacity 0 حتى تمرّر إليها. لذا قد يُظهر التقاط الصفحة كاملة إطارات فارغة وكتلاً بيضاء. استخدم التحميل الفوري (eager) للصور المهمة، وافرض الحالة الظاهرة عند الطباعة، أو دع المحوّل يمرّر الصفحة ويفرض تحميل الصور الكسولة قبل الالتقاط.
<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; }
}صور من مواقع أخرى (CORS)
المخرجات المبنية على اللقطات تعيد رسم الصفحة على لوحة canvas. وتمنع المتصفحات قراءة بكسلات الصور القادمة من نطاقات أخرى ما لم يرسل خادمها ترويسات CORS، لذا قد تغيب هذه الصور عن تنزيل PDF أو PNG أو PPTX بينما تظهر سليمة في الطباعة. ضع الصور في ملف .zip بجانب ملف HTML، أو استضفها على خادم يرسل Access-Control-Allow-Origin، أو استخدم الطباعة / الحفظ بصيغة PDF.
حركات ظهور لا تكتمل أبداً
إذا كان العنصر مخفياً في نمطه الأساسي ولا يظهر إلا بالحركة، فإن أي شيء يوقف الحركة (ملف أنماط للطباعة، أو التقاط في لحظة خاطئة، أو إعداد تقليل الحركة) يُبقيه مخفياً. جمّد الحركات عند حالتها النهائية في المحوّل، واكتب الحركات بحيث تكون الحالة المرئية هي الافتراضية.
/* 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; } }
ملف أنماط طباعة جاهز للّصق
يجمع هذا القسم الحلول السابقة. أضفه في نهاية ملف CSS، وكيّف المحدِّدات مع صفحتك، ثم استخدم الطباعة / الحفظ بصيغة PDF. انتبه إلى السطر الأخير: فهو يوقف الحركات، لذا لا يكون آمناً إلا إذا كانت عناصرك المتحرّكة ظاهرة افتراضياً كما شرحنا أعلاه.
@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; }
}- صفحات مولَّدة بالذكاء الاصطناعي؟ يتضمّن دليل تحويل HTML من ChatGPT إلى PDF طلباً جاهزاً لتطلب من الذكاء الاصطناعي إضافة أنماط الطباعة.
- تصنع شرائح لا مستندات؟ اتبع قواعد شرائح HTML التي تصمد أمام التحويل.
- لمقارنة الطرق والإعدادات الأساسية، عُد إلى دليل تحويل HTML إلى PDF مجاناً.
أسئلة شائعة
لماذا يبدو ملف HTML في PDF مختلفاً عنه في المتصفح؟
الطباعة / الحفظ بصيغة PDF تطبّق قواعد الطباعة: حذف الخلفيات افتراضياً، وتكرار العناصر الثابتة، وفواصل صفحات داخل المحتوى. أما ملفات PDF المبنية على اللقطات فتنسخ الشاشة لكنها قد تلتقط قبل اكتمال الخطوط أو الرسوم أو الحركات. حدّد الطريقة ثم طبّق الحل المناسب.
كيف أحافظ على ألوان الخلفية عند حفظ HTML بصيغة PDF؟
أضف print-color-adjust: exact (مع النسخة ذات البادئة -webkit- لمتصفح Safari) على عنصر html، أو فعّل خيار رسومات الخلفية في نافذة الطباعة. أما ملفات PDF المبنية على اللقطات فتحتفظ بالخلفيات تلقائياً لأنها تنسخ الشاشة.
لماذا تظهر الرسوم البيانية فارغة في ملف PDF؟
كان الرسم ما زال في حركته، أو لم يُرسم بعد، لحظة الالتقاط. اضبط animation: false في Chart.js، وانتظر بضع ثوانٍ قبل الالتقاط، وأعد تحجيم الرسوم عند حدث beforeprint لتناسب عرض الصفحة.
كيف أمنع فاصل الصفحة من قطع صورة أو صف جدول؟
طبّق break-inside: avoid على الصور والأشكال والبطاقات وصفوف الجداول، وdisplay: table-header-group على thead لتكرار رؤوس الجداول. العنصر الأطول من صفحة سيُقسَم رغم ذلك، فاجعل هذه الكتل أقصر من صفحة واحدة.
لماذا لا يمكن تحديد النص في ملف PDF؟
بُني الملف من لقطات للصفحة (مثلاً عبر html2canvas وjsPDF)، فكل صفحة فيه صورة. استخدم بدلاً من ذلك الطباعة / الحفظ بصيغة PDF، إذ يحتفظ محرّك الطباعة في المتصفح بنص حقيقي قابل للتحديد والبحث.
جرّبه: محوّل HTML إلى PDF مجاناً
يعمل داخل متصفحك: بدون رفع، بدون تسجيل، بدون علامة مائية.
أداة مجانية من دورني، منصة الولاء بالألعاب للأنشطة التجارية.