打印html表,防止行跨越多个页面

时间:2017-11-24 18:37:45

标签: css printing webkit

我以编程方式生成html,以便为打印提供良好的渲染效果。

我必须打印可能跨越多个页面的表格。这带来了一些挑战,例如阻止细胞内容分布在两页上,如下所示:

enter image description here

我在this answer中找到了一个使用page-break-inside:avoid的解决方案,以及this answerdisplay: block使用了<tr>来阻止它们从垂直分裂。

但是,这也会导致行不再相互垂直对齐。我该如何解决这个问题?

以下是它的外观(以及浏览器如何在屏幕上呈现):

enter image description here

以下是打印的内容:

enter image description here

如何使打印输出对齐,与屏幕上的对齐方式相同,而不必失去display: block在分页符处保持单元格垂直完整的能力?它必须在macOS上的Webkit(Safari)中工作。

这里是完整的HTML代码。它跨越两页,以便人们可以检查单个单元格是否出现在下一页的一半和一半(这是不希望的):

<!DOCTYPE html><html><head><meta charset="utf-8"><style type="text/css">
th, td { border: 1px solid #aaa; }
@media print {
  table, tr, td, th {
    page-break-inside: avoid;
  }
  tr {
    display: block;
    page-break-before: auto;
  }
}
</style></head>
<body>
<table style="width:40%">
  <tr><th>A</th><th>B</th><th>C</th></tr>
  <tr><td>more text<br>1<br>2<br>3<br>4<br>5<br></td><td>more text</td><td>more text</td></tr>
  <tr><td>1<br>2<br>3<br>4<br>5<br>6<br></td><td>x</td><td>x</td></tr>
  <tr><td>1<br>2<br>3<br>4<br>5<br>6<br></td><td>x</td><td>x</td></tr>
  <tr><td>1<br>2<br>3<br>4<br>5<br>6<br></td><td>x</td><td>x</td></tr>
  <tr><td>1<br>2<br>3<br>4<br>5<br>6<br></td><td>x</td><td>x</td></tr>
  <tr><td>1<br>2<br>3<br>4<br>5<br>6<br></td><td>x</td><td>x</td></tr>
  <tr><td>1<br>2<br>3<br>4<br>5<br>6<br></td><td>x</td><td>x</td></tr>
  <tr><td>1<br>2<br>3<br>4<br>5<br>6<br></td><td>x</td><td>x</td></tr>
  <tr><td>1<br>2<br>3<br>4<br>5<br>6<br></td><td>x</td><td>x</td></tr>
  <tr><td>1<br>2<br>3<br>4<br>5<br>6<br></td><td>x</td><td>x</td></tr>
</table>
</body></html>

更新

我还尝试使用div代替table的{​​{3}}。这在打印时会产生略微不同的结果,但仍然很糟糕(现在单元格高度也是错误的):

this solution

2 个答案:

答案 0 :(得分:1)

添加

td, th {
  width: 10000px;
}

@media print { }内完成了使示例代码有效的技巧。

现在打印的列再次正确对齐,每行都停留在一个页面上,从不跨越两页。

适用于当前版本的Webkit(Safari),FF和Chrome(仅在macOS上进行测试)。

<强>警告:

不幸的是,以上并非万无一失。它仅适用于此示例,因为每行中的单元格具有相同的宽度。

一旦这些宽度是随机的,像10000px这样的过度像素宽度会再次弄乱列。

我发现的唯一解决方案是提供要使用的实际宽度。由于这是用于打印,并且因为我知道我想要打印成特定的纸张格式(例如DIN A4或US Letter),所以我可以准确地指定列宽。

因此,虽然此解决方案对于屏幕上的浏览器中的网页视图来说不是一个好的解决方案,但总宽度可能会有所不同,只要可以预测目标打印尺寸,这对于打印来说是一个很好的解决方案。

以下是完整的html代码,将列宽设置为4cm,2cm和3cm:

<!DOCTYPE html><html><head><meta charset="utf-8"><style type="text/css">
th, td { border: 1px solid #aaa; }
@media print {
  table, tr, td, th {
    page-break-inside: avoid;
  }
  tr {
    display: block;
    page-break-before: auto;
  }
  td:nth-child(1), th:nth-child(1) {
    width: 4cm;
  }
  td:nth-child(2), th:nth-child(2) {
    width: 2cm;
  }
  td:nth-child(3), th:nth-child(3) {
    width: 3cm;
  }
}
</style></head>
<body>
<table>
  <tr><th>A</th><th>B</th><th>C</th></tr>
  <tr><td>more text<br>1<br>2<br>3<br>4<br>5<br></td><td>more text</td><td>more text</td></tr>
  <tr><td>1 adasd<br>2<br>3<br>4<br>5<br>6<br></td><td>x</td><td>x</td></tr>
  <tr><td>1<br>2<br>3<br>4<br>5<br>6<br></td><td>x</td><td>x</td></tr>
  <tr><td>1<br>2<br>3<br>4<br>5<br>6<br></td><td>x</td><td>x</td></tr>
  <tr><td>1asd<br>2<br>3<br>4<br>5<br>6<br></td><td>x</td><td>x</td></tr>
  <tr><td>1<br>2<br>3<br>4<br>5<br>6<br></td><td>x</td><td>x</td></tr>
  <tr><td>1<br>2<br>3<br>4<br>5<br>6<br></td><td>xsdsdfsf</td><td>x</td></tr>
  <tr><td>1<br>2<br>3<br>4<br>5<br>6<br></td><td>x</td><td>x</td></tr>
  <tr><td>1<br>2 asda asdas<br>3<br>4<br>5<br>6<br></td><td>xasdada</td><td>x</td></tr>
  <tr><td>1<br>2<br>3<br>4 asdasd <br>5<br>6<br></td><td>x</td><td>x</td></tr>
</table>
</body></html>

答案 1 :(得分:1)

不依赖于固定列宽的此问题的另一种解决方案是将每个单元格的内容包装在display:block元素中,并将其设置为page-break-inside: avoid。如果您不想首先更改HTML,则可以在加载时动态更改DOM。我很懒,在以下示例中使用的是jQuery:

<!DOCTYPE html><html><head><meta charset="utf-8"><style type="text/css">
th, td { border: 1px solid #aaa; }
@media print {
  td hack {
    display: block;
    page-break-inside: avoid;
  }
}
</style>
  <script src="https://code.jquery.com/jquery-3.5.0.js"></script>
  <script>
    window.addEventListener('load', function() {
        $( "td" ).wrapInner( "<hack></hack>" );
    })  
  </script>
</head>
<body>
<table>
  <tr><th>A</th><th>B</th><th>C</th></tr>
  <tr><td>more text<br>1<br>2<br>3<br>4<br>5<br></td><td>more text</td><td>more text</td></tr>
  <tr><td>1 adasd<br>2<br>3<br>4<br>5<br>6<br></td><td>x</td><td>x</td></tr>
  <tr><td>1<br>2<br>3<br>4<br>5<br>6<br></td><td>x</td><td>x</td></tr>
  <tr><td>1<br>2<br>3<br>4<br>5<br>6<br></td><td>x</td><td>x</td></tr>
  <tr><td>1asd<br>2<br>3<br>4<br>5<br>6<br></td><td>x</td><td>x</td></tr>
  <tr><td>1<br>2<br>3<br>4<br>5<br>6<br></td><td>x</td><td>x</td></tr>
  <tr><td>1<br>2<br>3<br>4<br>5<br>6<br></td><td>xsdsdfsf</td><td>x</td></tr>
  <tr><td>1<br>2<br>3<br>4<br>5<br>6<br></td><td>x</td><td>x</td></tr>
  <tr><td>1<br>2 asda asdas<br>3<br>4<br>5<br>6<br></td><td>xasdada</td><td>x</td></tr>
  <tr><td>1<br>2<br>3<br>4 asdasd <br>5<br>6<br></td><td>x</td><td>x</td></tr>
</table>
</body></html>

结果看起来会有些不同:

Print Preview

您看到以下问题:

  • 该行已经从上一页开始(可以看作是表仍在继续的指示)
  • B和C列的内容根据横跨两页的行的总高度垂直居中,因此它似乎朝着A列的最高单元格顶部对齐。

但是该解决方案确实适用于WebKit浏览器,并且仍呈现为普通表。