wkhtmltopdf 转换:HTML table 不适合 A4

wkhtmltopdf conversion: HTML table does not fit within the A4

我创建了一个基本的 PHP 网页来生成公司员工每月工作时间的时间表。 table 中的工作时间和其他详细信息将以 JSON 格式通过 API 馈送到现在设置为虚拟关联数组的 PHP 变量中,包含一些随机数据(我认为这与问题无关,所以就够了)。

我使用名为 Layoutit 的有用工具设计了布局:https://www.layoutit.com/build

我目前正在处理的 PHP 页面稍后会嵌入到另一个 HTML 页面中,并且会有一个按钮,可以使用名为 [=60= 的命令行实用程序将其转换为 PDF ]wkhtmltopdf。到目前为止一切顺利,我有一个工作 PHP 文件,其中包含生成 table 的 foreach 循环。使用此命令 wkhtmltopdf http://192.168.64.2/empl_timesheet.php empl_timesheet.pdf 成功将我的 empl_timesheet.php 文件转换为 PDF 后,table 不会像我预期的那样自动调整大小,而且我的段落从它们的 div 父元素中溢出。

我知道我的代码片段不会在 Whosebug 代码片段查看器上正确显示,因为其中有一些 PHP,所以如果您想重现该行为,最好克隆 repo 或复制文件的内容并 运行 它们在 XAMP 或类似服务器上。我是用 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>

我的问题是,在使用 wkhtmltopdf 生成 PDF 时,避免这种意外行为(溢出 div 和段落)的正确方法是什么?我指的是下面的屏幕截图,它显示了 wkhtmltopdf 为我生成的内容。如此处所见,table 的一半被截断了。 使用该实用程序本身生成 PDF 看起来非常简单,并且在 Whosebug 上提出了几个主题,其中包含各种用例或其他用户在我之前遇到的问题。尽管如此,none 我找到的那些给了我解决问题的线索,这就是我决定在这里提出这个话题的原因。

我已经阅读了很多关于 Stack 的文章,其中一些我列在这里:

这里看不到代码片段,也没有提到修复: wkhtmltopdf -> Issue to FIT Html table in A4 (C#)

我的问题似乎与 Pankaj Pawar 在此处描述为不必要的空白 spaces 完全相反: wkhtmltopdf | Nested Table HTML to PDF | Blank Space issue

对我来说,问题是缺少 space 来适应 table,所以关于如何缩小我所谓的 jumbotron div 的任何建议都足以正确欢迎打印 table。

Mert 在评论说他缺少对所需行为的解释后编辑了他的问题,但也没有答案: wkhtmltopdf html table side line

这不完全是我的情况,因为我已经可以将它转换为 A4,只是我的布局不会像 HTML 格式那样:

因此,为了明确所需的行为,这里有打印文档的屏幕截图,我的目标是让我的网页尽可能接近,用 Google Lens 翻译。

我浏览过的其他 Whosebug 文章主要是关于版本相关的问题,所以仍然没有找到适合我的解决方案。

我尝试过但对我不起作用的其他方法是将页面大小设置为 A4 格式的大小:

@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;
 } 

您在此处看到的我的代码片段也可以在我的 GitHub 个人资料中找到。

在尝试调整页面大小时使其适合 A4 页面时无处不在的基本功能是 so-called“缩小以适合”。我找不到 wkhtmltopdf 文档中提到的这一点,但我们的 Whosebug 用户 Etienne Gautier 描述了一种非常巧妙的方法来实现这一点,方法是在本主题 here.

下使用此 wkhtmltopdf 命令行调整布局大小
    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 

我想知道为什么他没有将其格式化为答案而不是评论。然而,这个问题应该放在不同的线程中,因为它还提出了一个关于 CSS 的页面的问题,人们想用 wkhtmltopdf 进行转换。

就您溢出的 div 而言,这似乎是样式本身的问题。我的意思是你必须找到一种方法来动态调整那些被合并的 div 的大小。如果只是关于改装 table,有一个稍微 counter-intuitive 的方法 table-layout: fixed;

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

谁会想到“固定”在这种情况下的含义。

如果您只是在寻找一种方法来打印出页面以使其正确适合 CSS 而无需对 CSS 进行任何更正,那么我提到的命令行应该可以为您完成这项工作。