如何避免wkhtmltopdf的表格行内出现分页符


Answers:


149

2015年9月17日更新:检查您使用的版本:据说可以解决wkhtmltopdf 0.12.2.4的问题(我尚未检查)


这是wkhtmltopdf中的一个已知问题。webkit(WKhtmltopdf中的WK)使用的分页算法在大型表中效果不佳。我建议将表分解为较小的块,这些块更容易拆分为页面并大量使用css:

table, tr, td, th, tbody, thead, tfoot {
    page-break-inside: avoid !important;
}

还可以看看以下wkhtmltopdf问题,它们有有趣的评论,例如,讨论了表拆分问题。有一个JS解决方案可以以编程方式在168中拆分表,这可能会对您有所帮助(不过我不使用它)。

2013年11月8日更新 上面链接的第168期对此进行了很多讨论。有人设法编译了一个支持更好的表中断的wkhtmltopdf版本,但不幸的是,它似乎尚未正式发布,并且可能包含其他错误。我不知道如何获得它,也不知道如何在Windows上进行编译,但是任何有兴趣的人都可以在这里查看例如注释(请参见下面的新更新)。

更新2014年2月24日 您将很高兴听到在wkhtmltopdf 0.12中,此功能以及其他功能已得到很大改进。但是,在开始使用任何新版本之前,请等待0.12.1并进行彻底测试,尽管使用antialize的新手做的很棒(ashkulz摇滚),但它仍然有些不稳定!保持更新在wkhtmltopdf.orggithub上。Google代码网站已过时,并且正在缓慢迁移。


1
谢谢你提供的详情。0.12.1版解决了分页符问题。
Nidhi Sarvaiya 2014年

1
请注意,此解决方案仅适用于最新的0.12.1版本。以前的任何方法仍然无效。
塞林2014年

4
我为此挣扎了几天。原来我的桌子是在风格为div的div中的display: inline-block。将其更改为,block然后进行更改,所有这些都开始起作用!

2
@Nenotlep感谢您的回答。是的,我已经发布了一个与此有关的新问题:stackoverflow.com/q/36334330/3391783-有趣的是,这一切似乎都可以在0.12.1或0.12.2的版本中恢复工作,并在0.12中再次被破坏。 3种版本。
low_rents's

2
@DjDacSaunders WKHTMLTOPDF是一个hack,而不是纯html-> pdf工具。这样做的目的是将很长的文档呈现为分页格式。我们对此有任何控制权,这一事实非常棒。如果您想改善绝对最佳的联系方式,那就是wkhtml的上游,它可以是QT项目,也可以是WebKit项目。我预言这件事不会改变,因为将Web网页呈现为PDF文件并不是WebKit真正要做的事情:/要完全控制,也许可以尝试使用PrinceXML。(x)HTML不是打印格式,该问题的“解决方案”始终是黑客。
乔尔·佩尔顿

18

这是旧文章,但是由于我浪费大量时间试图找到适当的解决方案,所以我将其放在此处,也许对某人有用。

所以从我读到的问题来看

page-break-inside: avoid

是它不起作用。但是实际上,如果将其设置在具有display:block预期效果的元素上(如SO中所指出)。所以对于表CSS的简单结构

td div, th div{
    page-break-inside: avoid;
}

和表结构

<table>
....
<tr>
    <td><div>some text</div></td>
    <td><div>more text</div></td>
</tr>
....
</table>

将按预期工作。

我对行距的情况比较复杂,因此从上面的解决方案是将其破坏成和平,这不是期望的效果。我使用div来解决每行跨行的问题。我的jQuery JS可以完成所有工作:

$(window).load(function () {
    var sizes = {};
    $('#the_table tr:first th').each(function (a, td) {         
        var w = $(td).width();
        if (sizes.hasOwnProperty('' + a)) {
            if (sizes['' + a] < w)
                sizes['' + a] = w;
        }
        else {
            sizes['' + a] = w;
        }
    });

    var tableClone = $('#the_table').clone();
    $('#the_table').replaceWith('<div class="container"></div>');

    var curentDivTable;
    var cDiv = $('.container');
    tableClone.find('tr').each(function (i, ln) {
        var line = $(ln);
        if (line.hasClass('main_row')) {
            var div = $('<div class="new-section"><table><tbody>')
            currentDivTable = div.find('tbody');
            cDiv.append(div);               
        }
        currentDivTable.append(line);
    });
    //optional - maybe in % its better than px
    var sum = 0;
    $.each(sizes, function (a, b) {
        sum += b;
    });
    var widths = {};
    $.each(sizes, function (a, b) {
        var p = Math.ceil(b * 100 / sum);
        widths['' + a] = p + '%';
    });
    //setup
    $('.container table').each(function (a, tbl) {
        $(tbl).find('tr:first td, tr:first th').each(function (b, td) {
            $(td).width(widths['' + b]);
        });
        $(tbl).addClass('fixed');
    });
});

CSS:

div.new-section {
    page-break-inside: avoid;
}
.container, .new-section, .new-section table.fixed{
    width: 100%;
}

.new-section table.fixed{
    table-layout:fixed;
}

我不知道是否需要所有东西,我也不认为它完美无缺,但确实可以完成。仅在铬上测试


16

从0.12开始,此问题已解决,但有时,当表太长而无法放入页面时,wkhtmltopdf将其分为两部分,并在新页面上重复列标题,并且这些列标题似乎重叠在第一行。

我在wkhtmltopdf github问题部分中找到了针对此问题的临时解决方案:https : //github.com/wkhtmltopdf/wkhtmltopdf/issues/2531

只需将此行添加到您的视图CSS:

tr {
  page-break-inside: avoid; 
}

这实际上有帮助。谢谢!!不知道为什么这不是默认行为。
JosephK

6

经过数天的研究,我终于找到了完美的解决方案。您可以参考phpwkhtmltopdf这个项目。查看目录article,您将找到针对3个问题的3个解决方案。简而言之,最终的解决方案是添加CSS样式

thead {
    display: table-row-group;
}
tr {
    page-break-before: always;
    page-break-after: always;
    page-break-inside: avoid;
}
table {
    word-wrap: break-word;
}
table td {
    word-break: break-all;
}

如果你是中国人,随时检查本网站关于wkhtmltopdf,你一定想知道这些 退房的要点,如果你想为wkhtmltopdf要点


这对我有用。我正在使用wkhtmltopdf 0.12.4。谢谢!
雨果

太好了,这就是为我做的。谢谢!!!
fafafooey


5

在我的特殊情况下,由于某种原因,以前的答案都对我无效。最终起作用的实际上是几件事的组合。

  1. 我安装(在Ubuntu 16.04)的Wkhtmltopdf Python包装称为pdfkit使用PIP 3,然后,而不是通过安装Wkhtmltopdf易于得到我通过下面的脚本安装了静态二进制(版本0.12.3),从这里取

    #!/bin/sh
    
    sudo apt-get install -y openssl build-essential xorg libssl-dev
    wget http://download.gna.org/wkhtmltopdf/0.12/0.12.3/wkhtmltox-0.12.3_linux-generic-amd64.tar.xz
    tar -xJf wkhtmltox-0.12.3_linux-generic-amd64.tar.xz
    cd wkhtmltox
    sudo chown root:root bin/wkhtmltopdf
    sudo cp -r * /usr/
    
  2. 添加了此CSS(如此处答案之一所示):

    tr, td div, th div{
        page-break-inside: avoid;
    }
    
  3. 然后按照此处建议的那样添加<thead><tbody>标记(如果没有这些标记,表仍然会以难看的方式破坏):

    <table>
        <thead>
            <tr>
                <th>Column 1</th>
                <th>Column 2</th>
            </tr>
        </thead>
    
        <tbody>
            <tr>
                <td>Value 1</td>
                <td>Value 2</td>
            </tr>
        </tbody>
    </table>
    

通过这些修改,我现在可以成功地使用Mako模板生成HTML,然后将其提供给Wkhtmltopdf并获得漂亮的分页PDF。


4

我尝试了对表的所有方式的操作,但是尝试执行的任何操作都无法阻止将分页符置于行的中间。无奈之下,我尝试了不同的版本,并发现了以下内容:

Wkhtmltopdf 0.12.2.1:错误

Wkhtmltopdf 0.12.3:错误

Wkhtmltopdf 0.12.1:好

我的解决方案是将版本降级到0.12.1,从而解决了我的问题。当然,它们的出现可能部分是由于我的html并不是超级OCD,但是由于HTML是在TinyMCE内部(由用户生成)的,所以我实际上没有太多选择。

另外,嵌套表对我而言在任何版本中均不起作用。


对我而言,0.12.1不能解决问题,并且无法解决
UnixAgain 17'Dec 27,15

2

经过大量的试用n错误后,我遇到了相同的问题,此CSS解决了该问题

tr { display: inline-table; }


2

如何在不中断tr的情况下在pdf中使用分页符?

这是可以在任何html文件中使用的解决方案.....

开始您的tr后,您必须在tr内加入一个div并将此CSS赋予div:

<tr>
      <div style="page-break-inside:avoid !important; page-break-after:auto !important; overflow: hidden; display:block !important; width:100% ">
     </tr>


1

以上答案对我没有用。我必须专门禁用pdfkit配置中的zoom选项。

PDFKit.configure do |config|

  config.default_options = {
    print_media_type: false,
    page_size: "A4",
    encoding: "UTF-8",
    ## Make sure the zoom option is not enabled!
    ## zoom: '1.3',
    disable_smart_shrinking: false,
    footer_right: "Page [page] of [toPage]"
  }

end

1

对于仍然对此有疑问的任何人,要记住的一件事是桌子必须是body的直接子对象,否则css将无法正常工作(至少这就是我所发生的事情)。


对我来说不是这种情况-我什至可以确认嵌套表也尊重分页符...对我来说,问题更多是Mac OS与Ubuntu ...
Petrov

我有一个类似的问题:我的表在一个已display: table-cell;应用的div内。使这些样式@media only screen固定的分页符。如果无法使分页符正常工作,请尝试通过分阶段删除一半CSS并查看其是否起作用来进行分而治之。
Leslie Viljoen'7

1

我发现了这个荒谬的解决方案,但对我来说效果很好:)

我只是把一个很长的rowspan列像这样

<td rowspan="XXX TOTAL ROWS" style="width:0px"></td>

然后表格不会中断。


1

另一种选择:将每个tr在其自己的tbody,然后应用Peage酒店休息CSS规则tbody。表支持多个tbody

有点额外的标记,但对我来说不错。


我在一组tr元素上进行了尝试-将它们包装在单独的tbody元素中-试图将某些行集合保持在一起。没有效果。在没有“ page-break-inside:避免;”的情况下执行此方法。再次,“ tr”元素上的“ |”导致返回到页眉顶部的打印数据(“默认”行为)。
JosephK '17

是的,我现在在tbody和tr和td上都应用相同的“ page-break-inside:avoid”规则:“ tbody,tbody> tr,tbody> tr> td,tbody> tr> th {page-break-inside:避免;}”在大多数情况下似乎有效。
Troy Morehouse

谢谢,但是尝试了一下。在我的行行中间,它仍然是分页符。我还尝试将一个类添加到tbody中,并在类中使用css加上“ avoid”-无效。我希望我知道这实际上是对css规则的“作用”-也许可以通过某种方式使它认为一组trs确实是“一行”-但是由于将tr 2x +变高也会破坏它,所以我猜不。也许有人会在另外10年内提供可用的HTML到PDF解决方案,但是我认为他们正在等待直接的神经数据传输。
JosephK

1

我结合了一些建议的解决方案解决了这个问题。

我将表包装在div中,并定义了以下CSS。

.wrapping-div {
        display: block;
        page-break-inside: avoid !important;
    }

.wrapping-div table, .wrapping-div tbody, .wrapping-div tr, .wrapping-div td, .wrapping-div th {
        page-break-inside: avoid !important;
    }

完成后的表结构定义为以下示例:

<div class="wrapping-div">
 <table>
  <tbody>
   <tr>
    <th>
      header
    </th>
    <td>
      content
    </td>
   </tr>
  </tbody>
 </table>
</div>

我不需要在td或th标签内创建任何div。

我在尝试解决问题时注意到的重要事项:

  • 表中必须包含琴身
  • div必须具有display:块
  • 当一个表不适合页面时,它将自动将整个表移到下一页(我还没有尝试使用大表)
  • 如果仅从CSS中删除“ .wrapping-div table”选择器,它将允许将表拆分为两页,但是将正确地呈现它,而不会在两页中破坏一个单元格(就像Word上的默认行为一样) )

我希望这有帮助。



1

为了避免分页符,我们可以使用分页符避免css选项。

tr { page-break-inside: avoid; }

中断所有内容(图像/文本),使其出现在下一页中

.sample-image { page-break-before: always; }

0

你有桌子头吗?和桌子的身体?

<table>
<tbody>
<tr><th>Name</th><th>Value</th></tr>
<tr><td>url</td><td>stackoverflow.com</td></tr>
<tr><td>ip</td><td>123.123.123.123</td></tr>
</tbody>
</table>

这是表的正确格式,尽管大多数浏览器都不太在乎,但如果您缺少或标记,我建议您先尝试添加这些格式,这样的转换就可以像您提到的那样进行转换<tbody><th>

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.