我希望每个打印页面都重复我的表格标题,但Google Chrome似乎不支持<thead>
标记...有没有办法解决这个问题?我正在使用Google Chrome v13.0.782.215。
表格代码非常简单......没什么特别的:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<style type="text/css" media="all">
@page {
size: landscape;
margin-top: 0;
margin-bottom: 1cm;
margin-left: 0;
margin-right: 0;
}
table {
border: .02em solid #666; border-collapse:collapse;
width:100%;
}
td, th {
border: .02em solid #666; font-size:12px; line-height: 12px;
vertical-align:middle; padding:5px; font-family:"Arial";
}
th { text-align:left; font-size:12px; font-weight:bold; }
h2 { margin-bottom: 0; }
</style>
</head>
<body>
<h2>Page Title</h2>
<table>
<thead>
<tr class="row1">
<th><strong>Heading 1</strong></th>
<th><strong>Heading 2</strong></th>
<th><strong>Heading 3</strong></th>
<th><strong>Heading 4</strong></th>
<th><strong>Heading 5</strong></th>
</tr>
</thead>
<tbody>
<tr class="row2">
<td width="30">...</td>
<td width="30">...</td>
<td width="90">....</td>
<td width="190">...</td>
<td width="420">...</td>
</tr>
<tr class="row1">
<td width="30">...</td>
<td width="30">...</td>
<td width="90">....</td>
<td width="190">...</td>
<td width="420">...</td>
</tr>
....
</tbody>
</table>
</body>
</html>
欢迎任何有关此事的见解。
答案 0 :(得分:47)
更新2017-03-22:重复表标题最终已在Chrome中实现了!(实际上,我认为它们是在不久前实施的。)这意味着您可能不需要这个解决方案了;只需将列标题放在<thead>
标记中即可。仅在以下情况下使用以下解决方案:
解决方案(已废弃)
下面的代码演示了我在多页表打印中找到的最佳方法。它具有以下特点:
......以及以下已知限制:
<thead>
(显然最重要的是allowed to have <tfoot>
(虽然Chrome兼容的页脚是technically possible)<caption>
margin
;要在表格上方或下方添加空白区域,请插入空白div并在其上设置底部边距border-width
和line-height
)必须位于px
不能通过将宽度值应用于单个表格单元格来设置列宽;您应该让单元格内容自动确定列宽,或者如果需要,使用<col>s
设置特定宽度
表格不能(轻松)在JS运行后动态更改
代码
<!DOCTYPE html>
<html>
<body>
<table class="print t1"> <!-- Delete "t1" class to remove row numbers. -->
<caption>Print-Friendly Table</caption>
<thead>
<tr>
<th></th>
<th>Column Header</th>
<th>Column Header</th>
<th>Multi-Line<br/>Column<br/>Header</th>
</tr>
</thead>
<tbody>
<tr>
<td></td>
<td>data</td>
<td>Multiple<br/>lines of<br/>data</td>
<td>data</td>
</tr>
</tbody>
</table>
</body>
</html>
<style>
/* THE FOLLOWING CSS IS REQUIRED AND SHOULD NOT BE MODIFIED. */
div.fauxRow {
display: inline-block;
vertical-align: top;
width: 100%;
page-break-inside: avoid;
}
table.fauxRow {border-spacing: 0;}
table.fauxRow > tbody > tr > td {
padding: 0;
overflow: hidden;
}
table.fauxRow > tbody > tr > td > table.print {
display: inline-table;
vertical-align: top;
}
table.fauxRow > tbody > tr > td > table.print > caption {caption-side: top;}
.noBreak {
float: right;
width: 100%;
visibility: hidden;
}
.noBreak:before, .noBreak:after {
display: block;
content: "";
}
.noBreak:after {margin-top: -594mm;}
.noBreak > div {
display: inline-block;
vertical-align: top;
width:100%;
page-break-inside: avoid;
}
table.print > tbody > tr {page-break-inside: avoid;}
table.print > tbody > .metricsRow > td {border-top: none !important;}
/* THE FOLLOWING CSS IS REQUIRED, but the values may be adjusted. */
/* NOTE: All size values that can affect an element's height should use the px unit! */
table.fauxRow, table.print {
font-size: 16px;
line-height: 20px;
}
/* THE FOLLOWING CSS IS OPTIONAL. */
body {counter-reset: t1;} /* Delete to remove row numbers. */
.noBreak .t1 > tbody > tr > :first-child:before {counter-increment: none;} /* Delete to remove row numbers. */
.t1 > tbody > tr > :first-child:before { /* Delete to remove row numbers. */
display: block;
text-align: right;
counter-increment: t1 1;
content: counter(t1);
}
table.fauxRow, table.print {
font-family: Tahoma, Verdana, Georgia; /* Try to use fonts that don't get bigger when printed. */
margin: 0 auto 0 auto; /* Delete if you don't want table to be centered. */
}
table.print {border-spacing: 0;}
table.print > * > tr > * {
border-right: 2px solid black;
border-bottom: 2px solid black;
padding: 0 5px 0 5px;
}
table.print > * > :first-child > * {border-top: 2px solid black;}
table.print > thead ~ * > :first-child > *, table.print > tbody ~ * > :first-child > * {border-top: none;}
table.print > * > tr > :first-child {border-left: 2px solid black;}
table.print > thead {vertical-align: bottom;}
table.print > thead > .borderRow > th {border-bottom: none;}
table.print > tbody {vertical-align: top;}
table.print > caption {font-weight: bold;}
</style>
<script>
(function() { // THIS FUNCTION IS NOT REQUIRED. It just adds table rows for testing purposes.
var rowCount = 100
, tbod = document.querySelector("table.print > tbody")
, row = tbod.rows[0];
for(; --rowCount; tbod.appendChild(row.cloneNode(true)));
})();
(function() { // THIS FUNCTION IS REQUIRED.
if(/Firefox|MSIE |Trident/i.test(navigator.userAgent))
var formatForPrint = function(table) {
var noBreak = document.createElement("div")
, noBreakTable = noBreak.appendChild(document.createElement("div")).appendChild(table.cloneNode())
, tableParent = table.parentNode
, tableParts = table.children
, partCount = tableParts.length
, partNum = 0
, cell = table.querySelector("tbody > tr > td");
noBreak.className = "noBreak";
for(; partNum < partCount; partNum++) {
if(!/tbody/i.test(tableParts[partNum].tagName))
noBreakTable.appendChild(tableParts[partNum].cloneNode(true));
}
if(cell) {
noBreakTable.appendChild(cell.parentNode.parentNode.cloneNode()).appendChild(cell.parentNode.cloneNode(true));
if(!table.tHead) {
var borderRow = document.createElement("tr");
borderRow.appendChild(document.createElement("th")).colSpan="1000";
borderRow.className = "borderRow";
table.insertBefore(document.createElement("thead"), table.tBodies[0]).appendChild(borderRow);
}
}
tableParent.insertBefore(document.createElement("div"), table).style.paddingTop = ".009px";
tableParent.insertBefore(noBreak, table);
};
else
var formatForPrint = function(table) {
var tableParent = table.parentNode
, cell = table.querySelector("tbody > tr > td");
if(cell) {
var topFauxRow = document.createElement("table")
, fauxRowTable = topFauxRow.insertRow(0).insertCell(0).appendChild(table.cloneNode())
, colgroup = fauxRowTable.appendChild(document.createElement("colgroup"))
, headerHider = document.createElement("div")
, metricsRow = document.createElement("tr")
, cells = cell.parentNode.cells
, cellNum = cells.length
, colCount = 0
, tbods = table.tBodies
, tbodCount = tbods.length
, tbodNum = 0
, tbod = tbods[0];
for(; cellNum--; colCount += cells[cellNum].colSpan);
for(cellNum = colCount; cellNum--; metricsRow.appendChild(document.createElement("td")).style.padding = 0);
cells = metricsRow.cells;
tbod.insertBefore(metricsRow, tbod.firstChild);
for(; ++cellNum < colCount; colgroup.appendChild(document.createElement("col")).style.width = cells[cellNum].offsetWidth + "px");
var borderWidth = metricsRow.offsetHeight;
metricsRow.className = "metricsRow";
borderWidth -= metricsRow.offsetHeight;
tbod.removeChild(metricsRow);
tableParent.insertBefore(topFauxRow, table).className = "fauxRow";
if(table.tHead)
fauxRowTable.appendChild(table.tHead);
var fauxRow = topFauxRow.cloneNode(true)
, fauxRowCell = fauxRow.rows[0].cells[0];
fauxRowCell.insertBefore(headerHider, fauxRowCell.firstChild).style.marginBottom = -fauxRowTable.offsetHeight - borderWidth + "px";
if(table.caption)
fauxRowTable.insertBefore(table.caption, fauxRowTable.firstChild);
if(tbod.rows[0])
fauxRowTable.appendChild(tbod.cloneNode()).appendChild(tbod.rows[0]);
for(; tbodNum < tbodCount; tbodNum++) {
tbod = tbods[tbodNum];
rows = tbod.rows;
for(; rows[0]; tableParent.insertBefore(fauxRow.cloneNode(true), table).rows[0].cells[0].children[1].appendChild(tbod.cloneNode()).appendChild(rows[0]));
}
tableParent.removeChild(table);
}
else
tableParent.insertBefore(document.createElement("div"), table).appendChild(table).parentNode.className="fauxRow";
};
var tables = document.body.querySelectorAll("table.print")
, tableNum = tables.length;
for(; tableNum--; formatForPrint(tables[tableNum]));
})();
</script>
如何工作(如果你不在乎,不要再读了;你需要的一切都在上面。)
Per @ Kingsolmn的请求,下面解释了该解决方案的工作原理。它没有涵盖JavaScript,这并不是严格要求的(虽然它确实使这项技术更容易使用)。相反,它专注于生成的HTML结构和相关的CSS,这是真正的魔术发生的地方。
以下是我们将要与之合作的表格:
<table>
<tr><th>ColumnA</th><th>ColumnB</th></tr>
<tr><td>row1</td><td>row1</td></tr>
<tr><td>row2</td><td>row2</td></tr>
<tr><td>row3</td><td>row3</td></tr>
</table>
&#13;
(为了节省空间,我只给了它3个数据行;显然,多页表通常会有更多数据行)
我们需要做的第一件事是将表拆分为一系列较小的表,每个表都有自己的列标题副本。我将这些较小的表称为 fauxRows 。
<table> <!-- fauxRow -->
<tr><th>ColumnA</th><th>ColumnB</th></tr>
<tr><td>row1</td><td>row1</td></tr>
</table>
<table> <!-- fauxRow -->
<tr><th>ColumnA</th><th>ColumnB</th></tr>
<tr><td>row2</td><td>row2</td></tr>
</table>
<table> <!-- fauxRow -->
<tr><th>ColumnA</th><th>ColumnB</th></tr>
<tr><td>row3</td><td>row3</td></tr>
</table>
&#13;
fauxRows本质上是原始表的克隆,但每个只有一个数据行。 (如果你的表有一个标题,但只有顶级的fauxRow应该包含它。)
接下来我们需要让fauxRows 牢不可破。那是什么意思? (注意 - 这可能是分页处理中最重要的概念。)&#34;坚不可摧&#34;是我用来描述不能在两页之间分割的内容块的术语*。当在这样的块占据的空间内发生分页时,整个块移动到下一页。 (请注意,我正在使用&#34;阻止&#34;非正式地在这里;我 指的是block level elements。)这种行为很有趣我们稍后会使用的副作用:它可以暴露由于分层或溢出而最初隐藏的内容。
我们可以通过应用以下任一CSS声明来使fauxRows牢不可破:
page-break-inside: avoid;
display: inline-table;
我通常使用两者,因为第一个用于此目的,第二个用于较旧/不兼容的浏览器。但是,在这种情况下,为了简单起见,我会坚持使用分页属性。请注意,添加此属性后,您不会看到表格外观有任何变化。
<table style="page-break-inside: avoid;"> <!-- fauxRow -->
<tr><th>ColumnA</th><th>ColumnB</th></tr>
<tr><td>row1</td><td>row1</td></tr>
</table>
<table style="page-break-inside: avoid;"> <!-- fauxRow -->
<tr><th>ColumnA</th><th>ColumnB</th></tr>
<tr><td>row2</td><td>row2</td></tr>
</table>
<table style="page-break-inside: avoid;"> <!-- fauxRow -->
<tr><th>ColumnA</th><th>ColumnB</th></tr>
<tr><td>row3</td><td>row3</td></tr>
</table>
&#13;
既然fauxRows是牢不可破的,如果在数据行中发生分页,它将转移到下一页及其附加的标题行。因此,下一页将始终在顶部显示列标题,这是我们的目标。但是现在所有额外的标题行看起来很奇怪。为了使它看起来像普通的表格,我们需要隐藏额外的标题,使它们只在需要时出现。
我们要做的是将每个fauxRow放在一个带有overflow: hidden;
的容器元素中,然后将其向上移动,以便标题被容器的顶部剪切掉。这也会将数据行重新移回到一起,使它们看起来是连续的。
你的第一直觉可能是为容器使用div,但我们将改为使用父表的单元格。我稍后会解释原因,但就目前而言,我们只需添加代码即可。 (再一次,这不会影响桌子的外观。)
table {
border-spacing: 0;
line-height: 20px;
}
th, td {
padding-top: 0;
padding-bottom: 0;
}
&#13;
<table> <!-- parent table -->
<tr>
<td style="overflow: hidden;">
<table style="page-break-inside: avoid;"> <!-- fauxRow -->
<tr><th>ColumnA</th><th>ColumnB</th></tr>
<tr><td>row1</td><td>row1</td></tr>
</table>
</td>
</tr>
<tr>
<td style="overflow: hidden;">
<table style="page-break-inside: avoid;"> <!-- fauxRow -->
<tr><th>ColumnA</th><th>ColumnB</th></tr>
<tr><td>row2</td><td>row2</td></tr>
</table>
</td>
</tr>
<tr>
<td style="overflow: hidden;">
<table style="page-break-inside: avoid;"> <!-- fauxRow -->
<tr><th>ColumnA</th><th>ColumnB</th></tr>
<tr><td>row3</td><td>row3</td></tr>
</table>
</td>
</tr>
</table>
&#13;
注意表格标记上方的CSS。我添加它有两个原因:首先,它阻止父表在fauxRows之间添加空格;第二,它使标题高度可预测,这是必要的,因为我们不使用JavaScript动态计算它。
现在我们只需要将fauxRows向上移动,我们将以负利润率进行调整。但它并不像你想象的那么简单。如果我们将一个负余量直接添加到fauxRow,当fauxRow碰到下一页时它将保持有效,导致页眉被页面顶部剪切。我们需要一种方法来消除负利润。
为了实现这一点,我们将在第一个fauxRow之后插入一个空div,并为其添加负边距。 (跳过第一个fauxRow,因为它的标题应始终可见。)由于边距位于单独的元素上,因此它不会跟随fauxRow到下一页,并且标题不会被剪裁。我将这些空div视为 headerHiders 。
table {
border-spacing: 0;
line-height: 20px;
}
th, td {
padding-top: 0;
padding-bottom: 0;
}
&#13;
<table> <!-- parent table -->
<tr>
<td style="overflow: hidden;">
<table style="page-break-inside: avoid;"> <!-- fauxRow -->
<tr><th>ColumnA</th><th>ColumnB</th></tr>
<tr><td>row1</td><td>row1</td></tr>
</table>
</td>
</tr>
<tr>
<td style="overflow: hidden;">
<div style="margin-bottom: -20px;"></div> <!-- headerHider -->
<table style="page-break-inside: avoid;"> <!-- fauxRow -->
<tr><th>ColumnA</th><th>ColumnB</th></tr>
<tr><td>row2</td><td>row2</td></tr>
</table>
</td>
</tr>
<tr>
<td style="overflow: hidden;">
<div style="margin-bottom: -20px;"></div> <!-- headerHider -->
<table style="page-break-inside: avoid;"> <!-- fauxRow -->
<tr><th>ColumnA</th><th>ColumnB</th></tr>
<tr><td>row3</td><td>row3</td></tr>
</table>
</td>
</tr>
</table>
&#13;
是的,我们已经完成了!在屏幕上,表格现在看起来正常,顶部只有一组列标题。在打印中,它现在应该有正在运行的标题。
如果您想知道为什么我们使用父表而不是一堆容器div,那是因为Chrome / webkit有一个错误导致div封闭的不可破坏的块将其容器带到下一页它。由于headerHider也在容器中,它不会像它应该的那样落后,这会导致剪切标题。只有当unbreakable块是div中具有非零高度的最顶层元素时才会出现此错误。
我在编写本教程时确实发现了一种解决方法:您只需在headerHider上显式设置height: 0;
并为其提供一个非零高度的空子div。然后你可以使用div容器。不过,我仍然更喜欢使用父表,因为它已经过更彻底的测试,并且通过将fauxRows重新绑定到一个表中,它在某种程度上挽救了语义。
编辑:我刚刚意识到JavaScript生成的标记略有不同,因为它将每个fauxRow放在一个单独的容器表中,并指定&#34; fauxRow&#34; className到它(容器)。这对于页脚支持是必需的,我打算在某一天添加,但从未这样做过。如果我要更新JS,我可能会考虑切换到div容器,因为我使用表的语义证明并不适用。
*有一种情况是,不可破坏的块可以在两个页面之间分割:当它超过可打印区域的高度时。你应该尽量避免这种情况;你基本上要求浏览器做不可能的事情,它会对输出产生一些非常奇怪的影响。
答案 1 :(得分:39)
我相信这是Chrome中的bug。
答案 2 :(得分:4)
现在可以使用jQuery在chrome中打印....请尝试使用此代码(我很遗憾忘记在修改之前谁是此代码的创建者 - 我的英语不好:D呵呵)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>DOCUMENT TITLE</title>
<link rel="stylesheet" type="text/css" href="assets/css/bootstrap.css"/>
<style type="text/css">
@media print{
table { page-break-after:auto;}
tr { page-break-inside:avoid;}
td { page-break-inside:auto;}
thead { display:table-header-group }
.row-fluid [class*="span"] {
min-height: 20px;
}
}
@page {
margin-top: 1cm;
margin-right: 1cm;
margin-bottom:2cm;
margin-left: 2cm;';
size:portrait;
/*
size:landscape;
-webkit-transform: rotate(-90deg); -moz-transform:rotate(-90deg);
filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);
*/
};
</style>
</head>
<body>
<div id="print-header-wrapper">
<div class="row-fluid">HEADER TITLE 1</div>
<div class="row-fluid">HEADER TITLE 2</div>
</div>
<div class="row-fluid" id="print-body-wrapper">
<table class="table" id="table_data">
<thead>
<tr><th>TH 1</th><th>TH 2</th></tr>
</thead>
<tbody>
<tr><td>TD 1</td><td>TD 2</td></tr>
<tr><td>TD 1</td><td>TD 2</td></tr>
<tr><td>TD 1</td><td>TD 2</td></tr>
<tr><td>TD 1</td><td>TD 2</td></tr>
<tr><td>TD 1</td><td>TD 2</td></tr>
<tr><td>TD 1</td><td>TD 2</td></tr>
<tr><td>TD 1</td><td>TD 2</td></tr>
<tr><td>TD 1</td><td>TD 2</td></tr>
<tr><td>TD 1</td><td>TD 2</td></tr>
<tr><td>TD 1</td><td>TD 2</td></tr>
<tr><td>TD 1</td><td>TD 2</td></tr>
<tr><td>TD 1</td><td>TD 2</td></tr>
<tr><td>TD 1</td><td>TD 2</td></tr>
<tr><td>TD 1</td><td>TD 2</td></tr>
<tr><td>TD 1</td><td>TD 2</td></tr>
<tr><td>TD 1</td><td>TD 2</td></tr>
</tbody>
</table>
<div id="lastDataTable"></div>
</div>
<script type="text/javascript">
jQuery(document).ready(function()
{
var printHeader = $('#print-header-wrapper').html();
var div_pageBreaker = '<div style="page-break-before:always;"></div>';
var per_page = 25;
$('#table_data').each(function(index, element)
{
//how many pages of rows have we got?
var pages = Math.ceil($('tbody tr').length / per_page);
//if we only have one page no more
if (pages == 1) {
return;
}
//get the table we're splutting
var table_to_split = $(element);
var current_page = 1;
//loop through each of our pages
for (current_page = 1; current_page <= pages; current_page++)
{
//make a new copy of the table
var cloned_table = table_to_split.clone();
//remove rows on later pages
$('tbody tr', table_to_split).each(function(loop, row_element) {
//if we've reached our max
if (loop >= per_page) {
//get rid of the row
$(row_element).remove();
}
});
//loop through the other copy
$('tbody tr', cloned_table).each(function(loop, row_element) {
//if we are before our current page
if (loop < per_page) {
//remove that one
$(row_element).remove();
}
});
//insert the other table afdter the copy
if (current_page < pages) {
$(div_pageBreaker).appendTo('#lastDataTable');
$(printHeader).appendTo('#lastDataTable');
$(cloned_table).appendTo('#lastDataTable');
}
//make a break
table_to_split = cloned_table;
}
});
});
</script>
</body>
</html>
答案 3 :(得分:2)
这是Webkit,Blink和Vivliostyle中尚未提供的增强功能,而不是其他更多“面向打印的格式化程序”(Firefox,IE)。
你可以查看issue for Google Chrome since version 4 here (6 years and 45 versions ago!),我们可以在这里看到它最近有一位老板(2016年2月),他们似乎正在努力。
有些人在谈论has been also held in the W3我们可以理解对其有用性的关注:
自重复表格页眉和页脚 碎片休息一般是有用的,我建议我们做一个 规范性要求并说UA必须重复页眉/页脚行 当一张桌子休息时。
同时,来自@DoctorDestructo和@thefredzx的JS和Jquery代码对于不使用Firefox或IE(大多数)的用户非常有用。
第一个知道包含此功能的新版本的人应该在这里注意到它,我们很多人会很感激。
答案 4 :(得分:1)
从我在Chrome设置display: table-row-group;
中的测试到thead停止了问题的发生。
例如,如果您尝试在没有样式的情况下打印下面的内容,您会在每个页面的顶部看到数字,但如果您添加样式,它只会出现在上下文中。
<style>
thead {
display: table-row-group;
}
</style>
<table>
<thead>
<tr>
<th>number</th>
</tr>
</thead>
<tbody id="myTbody">
</tbody>
</table>
<script>
for (i = 1; i <= 100; i++) {
document.getElementById("myTbody").innerHTML += "<tr><td>" + i + "</td></tr>";
}
</script>
答案 5 :(得分:0)
自2019年起的评论: 我奋斗了几个小时,标题中有一张图片
<table>
<thead>
<tr>
<td>
<img ...>
</td>
仅显示在首页上。
原因:
Chrome浏览器添加了@media print { img { page-break-inside: avoid !important; } }
样式
这导致图像无法在第2页及以后显示!
解决方案: 因此,只需插入一条规则
@media print { thead img { page-break-inside: auto !important; } }
停用此浏览器特定规则。
答案 6 :(得分:-3)
对于基于公司内部浏览器的系统,我建议用户使用firefox或IE;对于面向公众的网站,我认为如果用户使用chrome或具有类似限制的浏览器,我们无法真正做任何事情。还)