How can Puppeteer be configured to replicate the exact layout of an HTML document for PDF generation, including page breaks?

Currently, I am utilizing Puppeteer in order to create PDF files by using static HTML as the primary source:

const page = await browser.newPage();
await page.setContent(html); //the HTML content is retrieved from the file system

const pdf = await page.pdf({
    format: 'A4',
    printBackground: true,
    preferCSSPageSize: true
});

The same HTML content is made visible to the users on the front-end of my application so that they have a precise preview of the content before downloading the PDF.

To ensure that the size matches an A4 paper sheet, I am implementing CSS to adjust the width and height of the <body> tag in the HTML, while taking into consideration the margins.

For instance, the CSS styling may appear as follows:

@page {
    margin: 1cm; //instructs Puppeteer to incorporate a 1cm margin for printing the PDF
}

body {
    width: 19cm; // (21cm width minus 1cm margin on each side)
    height: 27.7cm // (29.7cm height minus 1cm margin top and bottom)
}

An issue that has arisen pertains to page breaks; at times, Puppeteer separates the lower content onto additional pages.

Here is how the HTML displays the lower section of the A4 page which the end-user visualizes.

Even though there seems to be adequate space for the final text row, it doesn't get cropped off.

However, when printed to PDF via Puppeteer, this is what happens:

In essence, the text gets distributed across two separate pages.

This fluctuating behavior is somewhat puzzling; occasionally, with varying paragraph lengths or text, the splitting of content across pages does not occur.

If you happen to know why Puppeteer exhibits this text-splitting behavior, I would greatly appreciate any insights or potential solutions as my exploration through the documentation has not yielded results thus far.

Thank you!

Answer №1

The issue lies in the discrepancy between your CSS settings regarding page size and the A4 pagesize that Chrome uses for printing.

Refer to this question and answer on resolving the problem, paying attention to the CSS settings provided in the accepted response.

CSS to set A4 paper size

The suggested solution involves utilizing the print media rule.

They have a demonstration with code snippet as follows:

@page {
  size: A4;
  margin: 0;
}
@media print {
  html, body {
    width: 210mm;
    height: 297mm;
  }
  /* ... additional rules ... */
}

I made slight adjustments to their demo to incorporate your Lorem Ipsum bulleted text. You can view it at http://jsfiddle.net/x7s2cntj/1/.

Click on run to see the outcome or test it using headless Chrome with puppeteer.

I excluded the stack overflow snippet due to possible extra CSS being applied within the snippet window.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Tips for adding a click event to a random "div" within a parent "div" element?

Upon clicking a main "Div", it splits into an n X n matrix with random colored divs. I now want to implement a click function for these random colorful divs that are scattered throughout the main "div". $(window).load(function() { var no = 1, $m = ...

Is there a way to continuously make changes to my MEAN stack code without needing to constantly restart `npm start`?

When running my MMEAN stack app (Mongoose, MongoDB, Express, AngularJS, and Node.js) using npm start, I find that every time I make a code change, I have to stop and start npm start again in order for the changes to appear on my web application. The consta ...

Prevent child div from resizing along with parent div during a resize event by utilizing the .resizable()

Check out this example here I am able to resize the div using jQuery, but I don't want the #spacer to have a fixed width at first because the content of the could vary in size. Even if I remove: width:100px; and try setting it to a percentage or ...

Identifying specific time intervals within an array of timestamps using jQuery

Currently, I am utilizing jQuery to manage a series of one-hour time intervals in an array. The array includes sets like: {hours[0] = '12a-1a', hours[1] = '1a-2a', hours[2] = '2a-3a', hours[3] = '2p-3p', hours[4 ...

Only implement the CSS styles if there are multiple elements that have the same class

I have 2 cards with the class card displayed within a card-stack. There can be any number of such cards. <div class="card-stack"> <div class="clear"><button name="clear" value="Clear all" onclick=&qu ...

Hover creates a duplicate dropdown menu

I'm facing an issue with the hover effect on my Metronic dropdown menu. When I hover over the menu button, everything works fine, but when I move to the options in the menu, it turns white. I suspect this might be due to two button activations happeni ...

Exploring the Differences in Site Navigation: PHP/HTML, Ajax, and CSS/Javascript

Lately, I've been weighing the pros and cons of using AJAX for my website navigation to transfer only necessary updated HTML elements. Alternatively, if there isn't a significant difference between new elements and current ones, just loading the ...

Information displays instantly in the initial milliseconds

When developing dynamic web pages with Nuxt, I encountered an issue in the pages directory where a file named _url.vue is located. The contents of this file are as follows: <template lang="pug"> div component( v-for= ...

Save a SQL query as a text file using Node.js

I'm having an issue with my code. I am trying to save the results of a SQL query into a text file, but instead of getting the actual results, all I see in the file is the word "object." const fs = require('fs'); const sql = require('mss ...

Tips on aligning a span element at the center of an image without losing its mouseover

<div class="pic"> <img src="image.jpg" height="250"/> <span class="text" style="display:none">text here</span> </div> <scriptsrc="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"> </scrip ...

Implementing a UserID field that automatically increments with each new entry

I am in the process of developing an API to extract and insert data from a database using the MEAN stack. My goal is to have the userID automatically generated, starting from 0, whenever a new entry is created in the userschema. var userSchema = new mong ...

Display additional information from a JSON file after choosing an ID with AngularJS Select

After saving a JSON file filled with information, I managed to successfully populate a select menu with the names of each element from the JSON data using this code snippet: <select ng-model="car.marca" ng-options="item.brakeId as item.name for item in ...

Performing a MySql query to retrieve data from two tables often leads to a high number of redundant entries

I'm currently utilizing the latest version 8.* of MySQL from Oracle. In my setup, I am using node.js in conjunction with express and have multiple tables that share the same structure involving an auto_increment id and some columns. For the index page ...

Generating a JavaScript object from a string to optimize its compatibility with datatables

This inquiry pertains to the plugin available at: var hidecols = '{"sClass": "Hide", "aTargets": [0]},{"sClass": "asdf", "aTargets": [1]},{"sClass": "qwer", "aTargets": [2]}'; var hidecolsobj = eval('(' + hidecols + ')'); ...

The "div width 100%" property functions flawlessly when tested locally, yet fails to operate on the live server

Hello, I recently launched my new website at www.leafletsdistributors.com. However, I'm encountering an issue with the Get in touch section (the light grey colored area). Despite setting the width to 100%, it's not fully extending across the scre ...

Mongoose TTL still expires despite condition being untrue

Currently, I am facing an issue with my mongoose Schema. I want the model to automatically delete itself after 60 seconds only if the field "paid" is set to false. However, whenever I use TTL (Time To Live), the document expires regardless of the value o ...

What could be causing my websocket server to not properly serve my HTML page?

I'm currently facing an issue with establishing a web socket connection using NodeJS in my app.js file. Despite declaring a listener on port 8080, the connection is not getting established and no logs are being generated in the console. My goal is to ...

Getting up and running with the NICE DCV SDK: A beginner's guide

Exploring the NICE DCV SDK provided by AWS has been my latest project. You can find the documentation here. However, I've hit a roadblock while trying to run the example code mentioned in the docs. My attempt to execute it on a node server resulted in ...

What is the most effective method for establishing indexes in MySQL database tables when using SailsJS?

Waterline offers built-in support for indexing, but not all adapters are compatible with this feature. The sails-mysql adapter, in particular, does not seem to support indexing. When attempting to include an index property in a model field, such as: use ...

Using Angular's ng-repeat prefilter with JavaScript

Is it possible to achieve the functionality of this angular js filter ng-repeat on a tr element using pure javascript? Could it be done in just one custom filter? Please note that showRow is a function that returns a boolean value, and searchString is a s ...