PDFMove
HTML'den PDF'e Dönüşümde CSS Print Mantığı Nasıl Çalışır?
Rehber

HTML'den PDF'e Dönüşümde CSS Print Mantığı Nasıl Çalışır?

7 dk okuma

Bir web sayfasını PDF'e çevirdiğinizde ekranda gördüğünüzden farklı bir sonuç alırsınız — ve bu bir hata değil, iki farklı düzen modeli arasındaki geçişin doğal sonucudur. Bu yazıda web sayfalarının nasıl sayfalara bölündüğünü, CSS'in baskı kurallarını ve dinamik içeriğin neden sorun çıkardığını açıklıyoruz.

İki düzen modeli

Web sayfası akan (continuous) bir ortamdır. Sayfa kavramı yoktur; içerik yukarıdan aşağıya sonsuz bir sütun olarak akar. Genişlik tarayıcı penceresine göre değişir ve düzen buna uyum sağlar.

PDF sayfalı (paged) bir ortamdır. Sabit boyutlu sayfalar vardır ve içerik bunlara dağıtılır.

CSS bu ikisini "ortam türü" (media type) kavramıyla ayırır ve farklı kurallar uygulanmasına izin verir.

@media print: iki farklı stil seti

Web sayfaları, ekran ve baskı için farklı stiller tanımlayabilir:

/* Herkes için */
body { font-family: sans-serif; }

/* Sadece ekranda */
@media screen {
  nav { position: fixed; background: #222; }
}

/* Sadece baskıda */
@media print {
  nav, .sidebar, .reklam, .yorumlar { display: none; }
  body { font-size: 11pt; color: #000; background: #fff; }
  a { text-decoration: underline; }
}

PDF üretimi print kurallarını kullanır. İyi tasarlanmış sitelerde bu, çıktının belirgin biçimde temizlenmesini sağlar:

  • Gezinme menüleri, kenar çubukları, reklamlar gizlenir.
  • Renkler basit ve okunaklı hâle gelir.
  • Yazı boyutları punto cinsinden ayarlanır.

Ama iki tür sorun da doğurur:

Aşırı gizleme. Bazı siteler baskı stilinde önemli bilgi kutularını da gizler.

Hiç stil olmaması. Baskı stili tanımlamamış siteler ekran düzenini olduğu gibi kullanır ve sonuç genellikle kötü olur — sabit konumlu menüler her sayfada tekrarlanabilir, koyu arka planlar sorun çıkarabilir.

CSS birimlerinin fiziksel karşılığı

Baskı bağlamında CSS birimleri kesin fiziksel değerlere sahiptir:

| Birim | Fiziksel karşılık | |---|---| | 1in (inç) | 2.54 cm | | 1cm | 1 cm | | 1mm | 1 mm | | 1pt (punto) | 1/72 inç | | 1pc (pika) | 12 punto | | 1px (CSS pikseli) | 1/96 inç |

Son satır kritik: 96 CSS pikseli tam olarak 1 inçtir.

Bu sabitin sonucu: bir A4 sayfa (210 mm = 8.27 inç genişlik), kenar boşlukları çıkarılmadan yaklaşık 794 CSS pikseli genişliğinde olur.

Ve bu, duyarlı tasarımlarda önemli bir etki yaratır. Birçok site şöyle kırılma noktaları kullanır:

@media (max-width: 768px) { /* tablet ve mobil düzen */ }
@media (max-width: 1024px) { /* küçük ekran düzeni */ }

794 piksel, ikinci kuralın altındadır ve bazı sitelerde birincinin de yakınındadır. Sonuç: PDF'te sayfa, masaüstünde gördüğünüzden farklı bir düzene geçer — sütunlar alt alta iner, menü hamburger simgesine dönüşür, görseller tam genişlik alır.

Bu, "PDF'te sayfa neden mobil gibi görünüyor?" sorusunun cevabıdır.

Çözüm yolları: yatay yönlendirme kullanmak (A4 yatayda ~1123 piksel), kenar boşluklarını azaltmak veya ölçekleme uygulamak.

@page: sayfanın kendisini tanımlamak

CSS'te @page kuralı, sayfa kutusunu tanımlar:

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

size için hazır boyutlar (A4, A3, Letter, Legal) veya özel ölçüler (size: 210mm 297mm) kullanılabilir. landscape anahtar kelimesi yönlendirmeyi değiştirir.

Sözde sınıflarla farklı sayfalara farklı kurallar uygulanabilir:

@page :first {
  margin-top: 5cm;   /* kapak sayfasında üstte boşluk */
}

@page :left {
  margin-left: 3cm;  /* ciltleme payı */
}

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

Bu, kitap tarzı çift taraflı çıktılarda ciltleme payı bırakmak için kullanılır.

Sayfa bölme algoritması

İçerik akışı, sayfa yüksekliği kadar dilimlenir. Bölme noktası bir öğenin ortasına denk geldiğinde tarayıcı bir karar vermek zorundadır.

CSS bu kararı yönlendiren özellikler sunar:

/* Bu öğe ikiye bölünmesin */
table, figure, .kart { page-break-inside: avoid; }

/* Bu öğeden önce yeni sayfa başlasın */
h1, .bolum { page-break-before: always; }

/* Bu öğeden hemen sonra bölme olmasın */
h2, h3 { page-break-after: avoid; }

Üçüncü kural özellikle faydalıdır: bir başlığın sayfanın en altında yalnız kalmasını (altındaki metin sonraki sayfada) önler.

Yetim ve dul satır kontrolü:

p {
  orphans: 3;  /* sayfanın altında bir paragraftan en az 3 satır kalsın */
  widows: 3;   /* sayfanın üstünde en az 3 satır olsun */
}

Bunlar tipografide klasik kurallardır: bir paragrafın tek satırının sayfa sonunda veya sayfa başında yalnız kalması kötü görünür.

Öğe türüne göre bölme davranışı:

| Öğe | Bölme davranışı | |---|---| | Metin bloğu | Satır sınırlarından bölünür | | Tablo | Satır sınırlarından bölünür | | Görsel | Bölünemez; kayar veya kesilir | | Konumlandırılmış öğe | Öngörülemez sonuçlar | | Flexbox / Grid | Destek tarayıcıya göre değişken |

Son iki satır önemli: mutlak konumlandırma ve modern düzen sistemleri, baskı bağlamında her zaman iyi davranmaz. Karmaşık bir grid düzeni sayfa sınırında beklenmedik biçimde bozulabilir.

Arka plan grafikleri neden basılmıyor

Yazdırma motorları, varsayılan olarak arka plan renklerini ve görsellerini basmaz. Bu, mürekkep tasarrufu amaçlı yerleşik bir davranıştır.

CSS'te bunu zorlamanın bir yolu vardır:

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

Tarayıcı yazdırma diyalogunda da "Arka plan grafikleri" seçeneği bulunur.

Bu ayar kapalıyken koyu zeminli tasarımlar felakete dönüşür: siyah zemin üzerine beyaz metin, zemin basılmayınca beyaz üzerine beyaz olur ve hiçbir şey görünmez.

Kendi HTML'inizi hazırlıyorsanız baskı stilinde renkleri tersine çevirmek daha güvenli bir yaklaşımdır:

@media print {
  .koyu-bolum { background: #fff; color: #000; }
}

Bağlantılar ve etkileşim

Köprüler genellikle PDF bağlantı açıklamalarına çevrilir ve tıklanabilir kalır. Bu, dönüştürücünün yeteneğine bağlıdır.

Basılı bir belgede bağlantının nereye gittiği görünmez. CSS ile adresi metne eklemek mümkündür:

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

Form alanları genellikle statik görünümlerine dönüşür. Bazı dönüştürücüler HTML formlarını PDF form alanlarına çevirebilir ama bu yaygın bir özellik değildir.

JavaScript etkileşimleri tamamen kaybolur: açılır menüler, sekmeler, akordeonlar. Kapalı durumdaki içerik PDF'te hiç görünmez — bir sıkça sorulan sorular bölümü akordeon şeklindeyse, PDF'te sadece sorular görünür, cevaplar görünmez.

Bu durum için baskı stilinde gizli içerikleri açmak gerekir:

@media print {
  .akordeon-icerik { display: block !important; }
}

Dinamik içerik ve zamanlama sorunu

Modern web sayfalarının çoğu içeriği sayfa yüklendikten sonra getirir: API çağrıları, tembel yüklenen görseller, sonsuz kaydırma.

Dönüştürücü, sayfayı belirli bir noktada "hazır" kabul edip PDF üretimini başlatır. Bu noktayı belirlemek için farklı stratejiler kullanılır:

  • Yükleme olayı (load event): Sayfanın ilk kaynakları indiğinde. Genellikle yetersizdir.
  • Ağ boşta kalma (network idle): Belirli bir süre yeni istek gelmediğinde. Daha iyi bir sinyal.
  • Sabit bekleme: Örneğin 3 saniye bekle. Kaba ama basit.
  • Öğe bekleme: Belirli bir CSS seçicisi görünene kadar bekle. En kesin yöntem ama yapılandırma gerektirir.

Sonsuz kaydırma kullanan sayfalarda hiçbir strateji tam içerik veremez — içerik yalnızca kullanıcı kaydırdıkça yüklenir ve dönüştürücü kaydırma yapmaz.

Tembel yüklenen görseller (lazy loading) aynı sorunu yaşar: görüntü alanına girmeyen görseller hiç yüklenmez ve PDF'te boş kalır.

Yazı tipi yükleme

Web yazı tipleri dış kaynaklardan indirilir:

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

Dönüştürme ortamı bu kaynağa erişemezse yazı tipi yüklenmez ve tarayıcı yedek yazı tipine düşer. Harf genişlikleri değiştiği için düzen kayar.

Ayrıca bir zamanlama sorunu vardır: yazı tipi yüklenmeden PDF üretilirse, sayfa yedek yazı tipiyle çizilir.

Kritik belgelerde çözümler:

  • Yazı tipini base64 olarak CSS'e gömmek.
  • Sistem yazı tipleri kullanmak.
  • Yazı tipi yüklenmesini bekleyen bir kontrol eklemek.

Özetle

HTML'den PDF'e dönüşüm, akan bir ortamdan sayfalı bir ortama geçiştir ve CSS bu geçişi @media print, @page ve sayfa bölme özellikleriyle yönetir. CSS pikselinin 1/96 inç olarak tanımlı olması, A4 sayfayı yaklaşık 794 piksel genişliğinde yapar ve duyarlı tasarımların mobil düzene geçmesine yol açar. Arka plan grafikleri varsayılan olarak basılmaz; koyu zeminli tasarımlarda bu ciddi bir sorundur. Sayfa bölme kararları page-break-inside, orphans ve widows gibi özelliklerle yönlendirilebilir ama bu kurallar sayfanın kendi kodunda tanımlı olmalıdır. Ve dinamik içerik, dönüştürücünün ne zaman "hazır" kararı verdiğine bağlı olarak eksik gelebilir — sonsuz kaydırma ve tembel yükleme kullanan sayfalarda tam içerik elde etmek genellikle mümkün değildir.

Sıkça Sorulan Sorular

CSS'te piksel bir fiziksel ölçüye nasıl karşılık geliyor?

Baskı bağlamında CSS pikseli 1/96 inç olarak tanımlanmıştır. Yani 96 piksel tam olarak 1 inç, yaklaşık 2.54 santimetre eder. Bu sabit sayesinde bir A4 sayfa (210 mm genişlik) yaklaşık 794 CSS pikseli genişliğinde olur. Duyarlı tasarımların PDF'te mobil düzene geçmesinin sebebi budur — 794 piksel, birçok sitede tablet veya mobil kırılma noktasının altındadır.

@page kuralı ne yapıyor?

Sayfanın kendisini tanımlar: boyut, yönlendirme ve kenar boşlukları. Örneğin @page { size: A4 landscape; margin: 1.5cm; } kuralı, çıktının A4 yatay olmasını ve her kenardan 1.5 cm boşluk bırakılmasını sağlar. Ayrıca :first, :left, :right sözde sınıflarıyla ilk sayfaya veya tek/çift sayfalara farklı kurallar uygulanabilir.

Sayfa bölme algoritması nasıl karar veriyor?

İçerik akışı, sayfa yüksekliği kadar dilimlenir. Bölme noktası bir öğenin ortasına denk gelirse, tarayıcı önce sayfa bölme özelliklerini (page-break-inside gibi) kontrol eder; kısıt yoksa öğeyi ikiye böler. Metin blokları satır sınırlarından bölünür, tablolar satır sınırlarından, görseller ise bölünemediği için ya tamamen sonraki sayfaya kayar ya da kesilir.

JavaScript ile üretilen içerik neden bazen PDF'e gelmiyor?

Çünkü dönüştürücü sayfayı belirli bir noktada 'hazır' kabul edip PDF üretimini başlatır. İçerik, sayfa yüklendikten sonra ayrı ağ istekleriyle geliyorsa ve dönüştürücü yeterince beklemiyorsa, o istekler tamamlanmadan çıktı alınır. Bazı araçlar ağ trafiğinin durmasını bekler ama sonsuz kaydırma veya periyodik güncelleme kullanan sayfalarda bu durum hiç oluşmaz.

Bu konuyu HTML/URL → PDF aracıyla hemen deneyin.

HTML/URL → PDF aracını dene