Issue with HTML to PDF Conversion in Node.js [closed]

6 days ago 6
ARTICLE AD BOX

When generating PDFs, the page border either touches or gets cut off at the page edges. Even when the border looks correct, the content overlaps the border during page breaks. I am facing multiple issues related to margin, padding, and page-breaking behavior.

I want to understand:

How to correctly set margins or padding based on border width

How page-breaking functionality should be implemented

How to prevent content from overlapping the page border

I am looking for a proper and easy solution, similar to Puppeteer, which is working well in production.

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Bio-Data - Traditional</title> <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"> <style> @import url('https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;700&family=Cormorant+Garamond:wght@400;600&family=Georgia:wght@400;600&display=swap'); * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: 'Georgia', serif; background: linear-gradient(135deg, #f5f1e8 0%, #e8dcc8 100%); min-height: 100vh; padding: 20px; display: flex; justify-content: center; align-items: center; } .container { max-width: 1038px; width: 100%; background: #fff; /* border: 3px solid #c9975b; border-radius: 15px;*/ padding: 25px; /* box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);*/ position: relative; } .corner-decoration { position: absolute; width: 80px; height: 80px; } .corner-top-left { top: -2px; left: -2px; background: linear-gradient(135deg, #c9975b 50%, transparent 50%); } .corner-top-right { top: -2px; right: -2px; background: linear-gradient(225deg, #c9975b 50%, transparent 50%); } .corner-bottom-left { bottom: -2px; left: -2px; background: linear-gradient(45deg, #c9975b 50%, transparent 50%); } .corner-bottom-right { bottom: -2px; right: -2px; background: linear-gradient(315deg, #c9975b 50%, transparent 50%); } .header,.header-print { text-align: center; background-repeat:no-repeat; background-size:contain; background-position: bottom center; background-image:url(data:image/jpeg;base64); } #dynamic-logo { margin-bottom: 8px; min-height: 50px; } #dynamic-logo img { height: 65px; width: auto; } .logo-text { font-size: 3rem; line-height: 1; color: #c9975b; text-shadow: 1px 1px 2px rgba(0,0,0,0.1); } .header-icon { width: 50px; height: 50px; margin: 0 auto 10px; fill: #c9975b; } .header .main-title { font-size: 2.5em; color: #c9975b; font-weight: normal; letter-spacing: 2px; margin-bottom:0px; } .header-lord-name { color: #c9975b; font-size: 16px; font-weight: 700; letter-spacing: 2px; margin-bottom: 8px; } .content { display: grid; grid-template-columns: 1fr 1fr; gap: 30px; background-image:url(data:image/jpeg;base64); background-repeat: repeat-y; background-size: contain; padding: 25px 30px; } .left-column { padding-right: 20px; } #root .contact-section{bottom: 70px;} .right-column { display: flex; flex-direction: column; gap: 20px; } .section { margin-bottom: 25px; } .section-title { color: #c9975b; font-size: 1.3em; margin-bottom: 12px; font-weight: bold; text-transform: uppercase; letter-spacing: 1px; display:inline-block; border-bottom:2px solid #c9975b; padding-bottom: 5px; } .section-content { color: #333; line-height: 1.8; } .field-item { margin-bottom: 8px; } .field-label { font-weight: bold; color: #222; } .head_spacing{display:none;} #profile-photo-container{text-align:right;justify-content: right;margin-bottom:0px;} #profile-photo-container img { width: 100%; max-width: 350px; height: auto; border-radius: 15px; border: 3px solid #c9975b; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2); object-fit: cover; max-height:550px; min-height:550px; } #gallery-container{text-align:right;display:block;} #gallery-container img { width: 100%; max-width: 350px; height: auto; border-radius: 15px; border: 3px solid #c9975b; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2); object-fit: cover; max-height:550px; min-height:550px; margin-top:20px; } .photo-container { display: flex; justify-content: center; margin-bottom: 20px; } .contact-section { grid-column: 1 / -1; text-align: center; position: absolute; bottom: 35px; left: 0px; right: 0px; } .contact-section h2 { color: #c9975b; font-size: 1.5em; margin-bottom: 5px; text-transform: uppercase; letter-spacing: 2px; } .contact-info { color: #333; font-size: 1.0em; line-height: 1.4; } #gallery-container .photo-card{border:none!important;padding:0px!important;margin:0px!important;} #gallery-container .photo-card img{float:right;vertical-align:top!important;} .photo-label{display:none!important;} .footer { position: absolute; display: block; width: 100%; bottom: 60px; z-index: 999; } .footer-bg,.footer-bg_inner1{ min-height:200px; position:relative; padding-bottom: 15px; background-repeat:no-repeat; background-size:contain; background-image:url(data:image/jpeg;base64,); } .footer-bg_inner{ position: absolute; bottom: 20px; left: 0px; z-index: 88; right: 0px; display:block; } /*.page-break{display:none;}*/ @media (max-width: 768px) { .content { grid-template-columns: 1fr; } .left-column { padding-right: 0; } .container { padding: 20px; } .header .main-title { font-size: 2em; } } .page_bg{display:none;} /* Print */ @media print { @page { size: A4; margin:20px 0px; } body { background: none; margin: 0px; padding:0px; -webkit-print-color-adjust: exact; print-color-adjust: exact; } #gallery-container { page-break-before: always; margin-top:0px; } .gallery-item-wrapper { page-break-inside: avoid; } .gallery-item-wrapper:nth-child(2n) { page-break-after: always; } .page-break { /*display:block;*/ break-after: page; page-break-after: always; } .page-break-auto{break-after: auto; page-break-after: auto;} /*.section{break-after: page; page-break-after: always; }*/ .footer-bg { display: block; position: fixed; bottom: -100px; /* Fix the footer to the bottom of the printed page */ width: calc(100% - 50px); text-align: center; left:25px;right:25px; background:none; z-index:20; } /*.footer-bg_inner{width:100%;position:absolute;z-index:88;bottom:-580px;}*/ .content{min-height:500px;position:relative;background:none;z-index:10;} .header { position:fixed; top:30px; left:25px; width: calc(100% - 50px); right:0px; display:block; background-position:top; z-index:11; background:none; } .page_margin{margin-top:120px;} .first_page.page_margin{margin-top:90px!important;} .container{margin:5px;} .page_bg{display:block;position:fixed;height:100%;margin-top:0px;bottom:0px;top:0px;left:0px;right:0px;background-image:url(data:image/jpeg;base64);background-size:auto 100%;background-repeat:no-repeat; background-position:center;z-index:5;} .head_spacing{height:100px;display:block;} #gallery-container .photo-item{margin-top:150px!important;break-after: always; /* Modern property */ page-break-before: always;} #dynamic-logo{margin-top:-25px;} } </style> </head> <body> <div class="container"> <div class="header"> <div id="dynamic-logo"><span class="logo-text"></span></div> <div id="dynamic-header-title" class="header-lord-name"></div> <div class="main-title" id="dynamic-main-title">Bio - Data</div> </div> <div class="head_spacing"></div> <div class="content"> <div class="left-column" id="sections-container"> <div class="section first_page page-break"> <h2 class="section-title">Personal Details</h2> <div class="section-content"> <div class="field-item"> <span class="field-label">Name: </span> </div> <div class="field-item"> <span class="field-label">Gender: </span> </div> <div class="field-item"> <span class="field-label">Date Of Birth: </span> </div> <div class="field-item"> <span class="field-label">Age: </span> </div> <div class="field-item"> <span class="field-label">Marital Status: </span> </div> <div class="field-item"> <span class="field-label">Height Unit: </span> <span class="field-value">Feet</span> </div> <div class="field-item"> <span class="field-label">Height: </span> </div> <div class="field-item"> <span class="field-label">Complexion: </span> </div> <div class="field-item"> <span class="field-label">Time Of Birth: </span> </div> <div class="field-item"> <span class="field-label">Place Of Birth: </span> </div> <div class="field-item"> <span class="field-label">Gotra/Caste: </span> </div> <div class="field-item"> <span class="field-label">Education: </span> </div> <div class="field-item"> <span class="field-label">Occupation: </span> </div> <div class="field-item"> <span class="field-label">Income: </span> </div> </div> </div> <div class="section page_margin page-break"> <h2 class="section-title">Family Details</h2> <div class="section-content"> <div class="field-item"> <span class="field-label">Father's Name: </span> </div> <div class="field-item"> <span class="field-label">Mother's Name: </span> </div> <div class="field-item"> <span class="field-label">Father's Occupation: </span> </div> <div class="field-item"> <span class="field-label">Mother's Occupation: </span> </div> <div class="field-item"> <span class="field-label">Brother Name (Elder): </span> </div> <div class="field-item"> <span class="field-label">Brother's Occupation (Elder): </span> </div> <div class="field-item"> <span class="field-label">Brother Name (Younger): </span> </div> <div class="field-item"> <span class="field-label">Brother's Occupation (Younger): </span> </div> <div class="field-item"> <span class="field-label">Sister Name (Elder): </span> </div> <div class="field-item"> <span class="field-label">Sister's Occupation (Elder): </span> </div> <div class="field-item"> <span class="field-label">Sister Name (Younger): </span> </div> <div class="field-item"> <span class="field-label">Sister's Occupation (Younger): </span> </div> <div class="field-item"> <span class="field-label">Family Type: </span> </div> <div class="field-item"> <span class="field-label">Family Values: </span> </div> </div> </div> <div class="section page_margin page-break"> <h2 class="section-title">Contact Details</h2> <div class="section-content"> <div class="field-item"> <span class="field-label">Contact Number: </span> </div> <div class="field-item"> <span class="field-label">Contact Email: </span> </div> <div class="field-item"> <span class="field-label">WhatsApp Number: </span> </div> <div class="field-item"> <span class="field-label">Contact Person: </span> </div> <div class="field-item"> <span class="field-label">Residential Address: </span> </div> <div class="field-item"> <span class="field-label">City: </span> </div> <div class="field-item"> <span class="field-label">State: </span> </div> </div> </div> <div class="footer-bg_inner"><div class="contact-section"> <h2>Contact Details</h2> <div class="contact-info"> <div class="field-item"><span class="field-label">Phone No.:</span> </div> <div class="field-item"><span class="field-label">Mail:</span> </div> </div> </div></div> </div> <div class="right-column"> <div class="photo-container" id="profile-photo-container"> </div> <div class="photo-container" id="gallery-container"> </div> </div> </div> <div class="footer-bg"></div> </div> <div class="page_bg">&nbsp;</div> <script> window.addEventListener('message', function (event) { if (event.data && event.data.type === 'UPDATE_BIODATA') { const data = event.data.data; const logoContainer = document.getElementById('dynamic-logo'); if (data.logo) { const isImage = data.logo.startsWith('http') || data.logo.startsWith('data:') || data.logo.match(/\.(jpeg|jpg|gif|png|webp|svg)$/i); if (isImage) { logoContainer.innerHTML = '<img src="' + data.logo + '" alt="Logo">'; } else { logoContainer.innerHTML = '<span class="logo-text">' + data.logo + '</span>'; } } else { logoContainer.innerHTML = ''; } const headerTitleEl = document.getElementById('dynamic-header-title'); headerTitleEl.innerText = data.lordName || data.headerTitle || ''; const mainTitleEl = document.getElementById('dynamic-main-title'); mainTitleEl.innerText = data.templateTitle || 'Bio - Data'; const profilePhotoArea = document.getElementById('profile-photo-container'); if (data.profilePhotoHTML) { profilePhotoArea.innerHTML = data.profilePhotoHTML; } const sectionsArea = document.getElementById('sections-container'); if (data.sectionsHTML) { sectionsArea.innerHTML = data.sectionsHTML; } const galleryArea = document.getElementById('gallery-container'); if (data.photosHTML) { galleryArea.innerHTML = data.photosHTML; } } }); </script> </body> </html> ```[complete file][1] [1]: https://limewire.com/d/MExQm#yuWRDRXdBk
Read Entire Article