apingaway
apingaway

Reputation: 53

wkhtmltopdf conversion: HTML table does not fit within the A4

I created a basic PHP webpage to generate a timesheet of the monthly working hours of employees of a company. The work hours and the other details in the table are to be feeded in JSON format through the an API into the PHP variables which are now set as a dummy associative arrays, containing some random data (I believe that is not relevant to the problem, so enough on this).

I designed the layout by using this helpful tool called Layoutit: https://www.layoutit.com/build

The PHP page I am currently working on would later be embeded within another HTML page and would have a button that will convert it to PDF with the command line utility called wkhtmltopdf. So far so good, I have a working PHP file with foreach cycles that generate the table. After successfully converting my empl_timesheet.php file to PDF with this command wkhtmltopdf http://192.168.64.2/empl_timesheet.php empl_timesheet.pdf, the table is not resized automatically as I expect and also my paragraphs overflow from their div parent elements.

I am aware my code snippet will not correctly display here on the StackOverflow snippet viewer because it has some PHP in it, so if you want to reproduce the behaviour it is best to clone the repo or copy the contents of the files and run them on a XAMP or similar server. I was doing it with XAMP.

* {
  font-family: 'Segoe UI', Tahoma, Verdana, sans-serif;
}

div {
  line-height: 0px;
}

/* @page {
  size: 21cm 29.7cm;
  margin: 30mm 45mm 30mm 45mm;
}

@media print {
body{
  line-height: 0px;
  width: 21cm;
  height: 29.7cm;
  margin: 30mm 45mm 30mm 45mm; 
  background:#f1f2f2;
 } 
} */

.thetable, .company_header, .signaturearea {
    border: 1px solid #323232;
    border-radius: 1px 1px 1px 1px;
}

.companyname, .timesheet, .dnplaceholder { 
  padding-left: 3.5em;
  padding-right: 3.5em;
  padding-top: 20%;
  float: left;
}

.l {
    padding: 2em;
    margin: 2em;
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;
    grid-template-rows: 1fr 1fr 1fr;
    gap: 0px 0px;
    grid-auto-flow: row;
    grid-template-areas:
        "company_header company_header company_header"
        "thetable thetable thetable"
        "signaturearea signaturearea signaturearea";
}

.company_header {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;
    grid-template-rows: 1fr 1fr 1fr;
    gap: 0px 0px;
    grid-auto-flow: row;
    grid-template-areas:
        ". companyname ."
        ". timesheet ."
        "dnplaceholder dnplaceholder .";
    grid-area: company_header;
}

.companyname {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;
    grid-template-rows: 1fr 1fr 1fr;
    gap: 0px 0px;
    grid-auto-flow: row;
    grid-template-areas:
        ". . ."
        ". . ."
        "companyname companyname companyname";
    grid-area: companyname;
}

.companyname {
    grid-area: companyname;
}

.timesheet { grid-area: timesheet; }

.dnplaceholder {  
  display: grid;
  grid-template-columns:1fr 1fr 1fr;
  grid-template-rows:1fr 1fr 1fr;
  gap: 0px 0px;
  grid-auto-flow: row;
  grid-template-areas:
    ". date ."
    ". name ."
    ". . .";
  grid-area: dnplaceholder;
}

.name { 
  grid-area: name;
}
.date { 
  grid-area: date;
}


.thetable { 
  grid-area: thetable; 
  overflow: auto;
  padding: 10%;
}

table {
  width: inherit;
}

.signaturearea {  
  display: grid;
  grid-template-columns:0.5fr 0.8fr 1fr;
  grid-template-rows:0.2fr 0.2fr 0.2fr;
  gap: 0px 0px;
  grid-auto-flow: row;
  grid-template-areas:
    ". . ."
    ". employeesignature ."
    ". . .";
  grid-area: signaturearea;
}

.employeesignature { 
  grid-area: employeesignature; 
  display: inline-block;
}
/* 
CUSTOM CSS TABLE 
ref link: https://dev.to/dcodeyt/creating-beautiful-html-tables-with-css-428l
*/
.thetable {
  border-collapse: collapse;
  font-size: 100%;
  font-family: sans-serif;
  box-shadow: 0 0 20px rgba(0, 0, 0, 0.15);
  text-align: center;
}

.thetable thead tr {
  background-color: #b9b9b9;
  color: #ffffff;
  border-bottom: 1px solid #b1b1b1;
  border-left: 1px solid #b1b1b1;
  border-right: 1px solid #b1b1b1;
}

.thetable th,
.thetable td {
    padding: 12px 15px;
    border-bottom: 1px solid #b1b1b1;
    border-left: 1px solid #b1b1b1;
    border-right: 1px solid #b1b1b1;
}

.thetable tbody tr {
  border-bottom: 1px solid #dddddd;
  border-bottom: 1px solid #b1b1b1;
  border-left: 1px solid #b1b1b1;
  border-right: 1px solid #b1b1b1;
}

.thetable tbody tr:nth-of-type(even) {
  background-color: #f3f3f3;
  border-bottom: 1px solid #b1b1b1;
  border-left: 1px solid #b1b1b1;
  border-right: 1px solid #b1b1b1;
}

.thetable tbody tr:last-of-type {
  border-bottom: 1px solid #b1b1b1;
  border-left: 1px solid #b1b1b1;
  border-right: 1px solid #b1b1b1;
}

/*.sum { 
  color: #009879;
}
*/

#jumbotron {
  padding: 6em;
  margin: 6em;
  box-shadow: 1px #b1b1b1;
  box-shadow: rgb(161, 161, 161) 5px 5px 15px 10px;
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>timesheet</title>
    <meta name="description" content="Source code by Svetlin I.">
    <meta name="author" content="Svetlin!">
    <!-- <link rel="stylesheet" href="stdz_style.css"> -->
    <link rel="stylesheet" href="corner.css">
    <link rel="stylesheet" href="timesheet_style.css?v=<?php echo time(); ?>">
</head>
<body>
    <!-- JUMBO with shadows -->
    <div id="jumbotron">  
        <!--  .l -->
        <div class="l">
            <div class="company_header">
                <div class="companyname">
                    <h3>
                        <!-- Company Name Ltd. -->
                    </h3>
                </div>
                <div class="timesheet">
                    <h4>
                        Work Hours Timesheet
                    </h4>
                </div>
                <div class="dnplaceholder">
                    <div class="date">
                        Month: Feb 22
                    </div>
                    <div class="name">
                        Name: Mad Max
                    </div>
                </div>
            </div>
                <!-- TABLE STYLED WITH CSS -->
                <div class="thetable">
                    <?php
                        $data = array();

                        $companyLogo = "https//www.companylogo.xyz/logo";
                        $month = "February 23"; 
                        $name = "Mad Max";

                        $data[] = ["workStart" => "07:00", "workEnd" => "15:45", "breaks" => "0:45",  "actualWorkHours" => "08,00", "placeholder" => "empty", "sick" => "empty", "vaccation"  => "empty", "holiday" => "empty", "recordedOn" => "04.02.2022", "remark" => "empty"]; 
                        $data[] = ["workStart" => "06:30", "workEnd" => "15:15", "breaks" => "0:45",  "actualWorkHours" => "08,00", "placeholder" => "empty", "sick" => "empty", "vaccation"  => "empty", "holiday" => "empty", "recordedOn" => "05.02.2022", "remark" => "empty"]; 
                        $data[] = ["workStart" => "07:30", "workEnd" => "16:15", "breaks" => "0:45",  "actualWorkHours" => "08,00", "placeholder" => "empty", "sick" => "empty", "vaccation"  => "empty", "holiday" => "empty", "recordedOn" => "06.02.2022", "remark" => "empty"]; 
                        $data[] = ["workStart" => "07:00", "workEnd" => "15:45", "breaks" => "0:45",  "actualWorkHours" => "08,00", "placeholder" => "empty", "sick" => "empty", "vaccation"  => "empty", "holiday" => "empty", "recordedOn" => "04.02.2022", "remark" => "empty"]; 
                        $data[] = ["workStart" => "06:30", "workEnd" => "15:15", "breaks" => "0:45",  "actualWorkHours" => "08,00", "placeholder" => "empty", "sick" => "empty", "vaccation"  => "empty", "holiday" => "empty", "recordedOn" => "05.02.2022", "remark" => "empty"]; 
                        $data[] = ["workStart" => "07:30", "workEnd" => "16:15", "breaks" => "0:45",  "actualWorkHours" => "08,00", "placeholder" => "empty", "sick" => "empty", "vaccation"  => "empty", "holiday" => "empty", "recordedOn" => "06.02.2022", "remark" => "empty"]; 
                        $data[] = ["workStart" => "07:00", "workEnd" => "15:45", "breaks" => "0:45",  "actualWorkHours" => "08,00", "placeholder" => "empty", "sick" => "empty", "vaccation"  => "empty", "holiday" => "empty", "recordedOn" => "04.02.2022", "remark" => "empty"]; 
                        $data[] = ["workStart" => "06:30", "workEnd" => "15:15", "breaks" => "0:45",  "actualWorkHours" => "08,00", "placeholder" => "empty", "sick" => "empty", "vaccation"  => "empty", "holiday" => "empty", "recordedOn" => "05.02.2022", "remark" => "empty"]; 
                        $data[] = ["workStart" => "07:30", "workEnd" => "16:15", "breaks" => "0:45",  "actualWorkHours" => "08,00", "placeholder" => "empty", "sick" => "empty", "vaccation"  => "empty", "holiday" => "empty", "recordedOn" => "06.02.2022", "remark" => "empty"]; 
                        $data[] = ["workStart" => "07:00", "workEnd" => "15:45", "breaks" => "0:45",  "actualWorkHours" => "08,00", "placeholder" => "empty", "sick" => "empty", "vaccation"  => "empty", "holiday" => "empty", "recordedOn" => "04.02.2022", "remark" => "empty"]; 
                        $data[] = ["workStart" => "06:30", "workEnd" => "15:15", "breaks" => "0:45",  "actualWorkHours" => "08,00", "placeholder" => "empty", "sick" => "empty", "vaccation"  => "empty", "holiday" => "empty", "recordedOn" => "05.02.2022", "remark" => "empty"]; 
                        $data[] = ["workStart" => "07:30", "workEnd" => "16:15", "breaks" => "0:45",  "actualWorkHours" => "08,00", "placeholder" => "empty", "sick" => "empty", "vaccation"  => "empty", "holiday" => "empty", "recordedOn" => "06.02.2022", "remark" => "empty"]; 
                        $data[] = ["workStart" => "07:00", "workEnd" => "15:45", "breaks" => "0:45",  "actualWorkHours" => "08,00", "placeholder" => "empty", "sick" => "empty", "vaccation"  => "empty", "holiday" => "empty", "recordedOn" => "04.02.2022", "remark" => "empty"]; 
                        $data[] = ["workStart" => "06:30", "workEnd" => "15:15", "breaks" => "0:45",  "actualWorkHours" => "08,00", "placeholder" => "empty", "sick" => "empty", "vaccation"  => "empty", "holiday" => "empty", "recordedOn" => "05.02.2022", "remark" => "empty"]; 
                        $data[] = ["workStart" => "07:30", "workEnd" => "16:15", "breaks" => "0:45",  "actualWorkHours" => "08,00", "placeholder" => "empty", "sick" => "empty", "vaccation"  => "empty", "holiday" => "empty", "recordedOn" => "06.02.2022", "remark" => "empty"]; 
                        $data[] = ["workStart" => "07:00", "workEnd" => "15:45", "breaks" => "0:45",  "actualWorkHours" => "08,00", "placeholder" => "empty", "sick" => "empty", "vaccation"  => "empty", "holiday" => "empty", "recordedOn" => "04.02.2022", "remark" => "empty"]; 
                        $data[] = ["workStart" => "06:30", "workEnd" => "15:15", "breaks" => "0:45",  "actualWorkHours" => "08,00", "placeholder" => "empty", "sick" => "empty", "vaccation"  => "empty", "holiday" => "empty", "recordedOn" => "05.02.2022", "remark" => "empty"]; 
                        $data[] = ["workStart" => "07:30", "workEnd" => "16:15", "breaks" => "0:45",  "actualWorkHours" => "08,00", "placeholder" => "empty", "sick" => "empty", "vaccation"  => "empty", "holiday" => "empty", "recordedOn" => "06.02.2022", "remark" => "empty"]; 
                        $data[] = ["workStart" => "07:00", "workEnd" => "15:45", "breaks" => "0:45",  "actualWorkHours" => "08,00", "placeholder" => "empty", "sick" => "empty", "vaccation"  => "empty", "holiday" => "empty", "recordedOn" => "04.02.2022", "remark" => "empty"]; 
                        $data[] = ["workStart" => "06:30", "workEnd" => "15:15", "breaks" => "0:45",  "actualWorkHours" => "08,00", "placeholder" => "empty", "sick" => "empty", "vaccation"  => "empty", "holiday" => "empty", "recordedOn" => "05.02.2022", "remark" => "empty"]; 
                        $data[] = ["workStart" => "07:30", "workEnd" => "16:15", "breaks" => "0:45",  "actualWorkHours" => "08,00", "placeholder" => "empty", "sick" => "empty", "vaccation"  => "empty", "holiday" => "empty", "recordedOn" => "06.02.2022", "remark" => "empty"]; 
                        $data[] = ["workStart" => "07:00", "workEnd" => "15:45", "breaks" => "0:45",  "actualWorkHours" => "08,00", "placeholder" => "empty", "sick" => "empty", "vaccation"  => "empty", "holiday" => "empty", "recordedOn" => "04.02.2022", "remark" => "empty"]; 
                        $data[] = ["workStart" => "06:30", "workEnd" => "15:15", "breaks" => "0:45",  "actualWorkHours" => "08,00", "placeholder" => "empty", "sick" => "empty", "vaccation"  => "empty", "holiday" => "empty", "recordedOn" => "05.02.2022", "remark" => "empty"]; 
                        $data[] = ["workStart" => "07:30", "workEnd" => "16:15", "breaks" => "0:45",  "actualWorkHours" => "08,00", "placeholder" => "empty", "sick" => "empty", "vaccation"  => "empty", "holiday" => "empty", "recordedOn" => "06.02.2022", "remark" => "empty"]; 
                        $data[] = ["workStart" => "07:00", "workEnd" => "15:45", "breaks" => "0:45",  "actualWorkHours" => "08,00", "placeholder" => "empty", "sick" => "empty", "vaccation"  => "empty", "holiday" => "empty", "recordedOn" => "04.02.2022", "remark" => "empty"]; 
                        $data[] = ["workStart" => "06:30", "workEnd" => "15:15", "breaks" => "0:45",  "actualWorkHours" => "08,00", "placeholder" => "empty", "sick" => "empty", "vaccation"  => "empty", "holiday" => "empty", "recordedOn" => "05.02.2022", "remark" => "empty"]; 
                        $data[] = ["workStart" => "07:30", "workEnd" => "16:15", "breaks" => "0:45",  "actualWorkHours" => "08,00", "placeholder" => "empty", "sick" => "empty", "vaccation"  => "empty", "holiday" => "empty", "recordedOn" => "06.02.2022", "remark" => "empty"]; 
                        $data[] = ["workStart" => "07:00", "workEnd" => "15:45", "breaks" => "0:45",  "actualWorkHours" => "08,00", "placeholder" => "empty", "sick" => "empty", "vaccation"  => "empty", "holiday" => "empty", "recordedOn" => "04.02.2022", "remark" => "empty"]; 
                        $data[] = ["workStart" => "06:30", "workEnd" => "15:15", "breaks" => "0:45",  "actualWorkHours" => "08,00", "placeholder" => "empty", "sick" => "empty", "vaccation"  => "empty", "holiday" => "empty", "recordedOn" => "05.02.2022", "remark" => "empty"]; 
                        $data[] = ["workStart" => "07:30", "workEnd" => "16:15", "breaks" => "0:45",  "actualWorkHours" => "08,00", "placeholder" => "empty", "sick" => "empty", "vaccation"  => "empty", "holiday" => "empty", "recordedOn" => "06.02.2022", "remark" => "empty"]; 
                        $data[] = ["workStart" => "07:00", "workEnd" => "15:45", "breaks" => "0:45",  "actualWorkHours" => "08,00", "placeholder" => "empty", "sick" => "empty", "vaccation"  => "empty", "holiday" => "empty", "recordedOn" => "04.02.2022", "remark" => "empty"];
                        

                        $dataHeader["day"] = "Day";
                        $dataHeader["workStart"] = "Work start";
                        $dataHeader["workEnd"] = "Work end";
                        $dataHeader["breaks"] = "Pause";
                        $dataHeader["actualWorkHours"] = "Actual Workhours";
                        $dataHeader["placeholder"] = "Placeholder";
                        $dataHeader["sick"] = "Sick Leave";
                        $dataHeader["vaccation"] = "Vaccation";
                        $dataHeader["holiday"] = "Holiday";
                        $dataHeader["recordedOn"] = "Recorded on:";
                        $dataHeader["remark"] = "Remark:";


                        $listKeys = ["day", "workStart", "workEnd", "breaks", "actualWorkHours", "placeholder", "sick", "vaccation", "holiday", "recordedOn", "remark"];
                    ?>

                    <div>
                        <table>
                            <thead>
                                <tr>
                                    <?php
                                        foreach($dataHeader as $x => $x_value) {
                                            echo "<th>" . $x_value . "</th>";
                                        } 
                                    ?>
                                </tr>            
                            </thead>

                            <tbody>

                                <?php
                                    $endday = 31;
                                    $currentDay = 1;
                                    foreach($data as $key=>$row) {
                                        echo "<tr>";
                                        echo "<td>" . $currentDay . "</td>";

                                        foreach($row as $key2=>$row2){
                                            echo "<td>" . $row2 . "</td>";
                                        }
                                        echo "</tr>";
                                        $currentDay += 1;
                                    }
                                ?>
                            </tbody>
                        </table>
                    </div>
                </div>
            <!-- END TABLE STYLED WITH CSS -->
                <!--  EMPLOYEE SIGNATURE -->
                    <div class="signaturearea">
                        <div class="employeesignature">
                            <p>Employee Signature:</p>                                        
                            <p><br/><br/><br/></p>      
                            <p><br/><br/><br/></p>                                                                          
                            <p>__________________________</p>                                        
                        </div>
                    </div>
                <!-- END EMPLOYEE SIGNATURE -->
        </div>
        <!-- END .l -->
    <!-- END JUMBOTRON with shadows -->
    </div>
</body>
</html>

My question is, what is the right way to avoid this unintended behaviour (overflowing divs and paragraphs) while generating the PDFs with wkhtmltopdf? I am referring to the screenshot below which shows what wkhtmltopdf generates for me. As seen there, half of the table is getting cut off. employee table after the PDF is generated Using the utility itself to generate PDFs looks pretty straight forward and there are several topics raised here on StackOverflow with various use cases or issues other users before me had. Nevertheless, none of those I found, gave me a clue on how to solve my problem and this is why I decided to raise the topic here.

I have read through numerous articles on Stack, some of them I list here:

Here code snippets are not to be seen and there is no fix mentioned: wkhtmltopdf -> Issue to FIT Html table in A4 (C#)

I seem to have exactly the opposite problem of what Pankaj Pawar has described here as unnecessary blank spaces: wkhtmltopdf | Nested Table HTML to PDF | Blank Space issue

For me the issue is the lack of space to fit the table, so any advice on how to scale down my so-called jumbotron div to be sufficient for properly printing the table are welcome.

Mert has edited his question after a remark that he is missing explanation of the desired behaviour but there is also no answer yet: wkhtmltopdf html table side line

This one is not exactly my case as I already can convert it in A4, just my layout wont be as it is in HTML format: convert html to pdf in a4 size wkhtmltopdf

So to make the desired behaviour clear, there is the screenshot of the printed document which I am aiming my webpage to resemble as closely as possible, translated with Google Lens. enter image description here

The other StackOverflow articles I have gone through are mostly about version-related issues, so still no luck in finding out a solution there for me.

Something else I have tried but did not work for me is setting the size of the page to be the size of the A4 format:

@page {
  size: 21cm 29.7cm;
  margin: 30mm 45mm 30mm 45mm;
}

@media print {
body{
  line-height: 0px;
  width: 21cm;
  height: 29.7cm;
  margin: 30mm 45mm 30mm 45mm; 
  background:#f1f2f2;
 } 

My code snippets you see here are also available on my GitHub profile.

Upvotes: 1

Views: 3033

Answers (2)

We upgraded from 0.12.4 to 0.12.6 in the course of a migration between servers and then got very unpredictable resizing problems. The pdfs were much too big. We did not find a solution and reverted back to 0.12.4. Something has changed.

Upvotes: 1

apingaway
apingaway

Reputation: 53

A basic functionality that is omnipresent when trying to resize page so they fit an A4 page is the so-called "Shrink to fit". I could not find this mentioned in the wkhtmltopdf documentation but our fellow StackOverflow user Etienne Gautier has described a pretty neat way of achieving this by resizing the layout with this wkhtmltopdf command line under this topic here.

    wkhtmltopdf --zoom 0.7 --margin-bottom "3mm" --                margin-top "3mm" --margin-left "3mm" --margin-right "3mm" http://path/to/your_php_file.php /path/to/your/pdf_output_file.pdf 

I wonder why he has not formatted it as an answer instead of a comment. Nevertheless, this question deserves to be in a different thread as it raises also a question regarding the CSS of a page that one would like to convert with wkhtmltopdf.

As far as your overflowing divs are concerned, this seems to be an issue with the styling itself. I mean that you would have to find a way to dynamically resize those divs that get merged. If it is only about refitting the table, there is a slightly counter-intuitive way of doing it with table-layout: fixed;

    table { 
    table-layout: fixed;
    width: 100%;
    }

Who would have thought what "fixed" would mean in this context.

If you are just looking for a way to print out the page so that it correctly fits in within without any corrections to the CSS, then the command line I mentioned should do the job for you.

Upvotes: 3

Related Questions