Если Google Chrome повторяет заголовки таблиц на печатных страницах

Я бы хотел, чтобы мои заголовки таблиц повторялись для каждой распечатанной страницы, но, похоже, 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>

Любое понимание этого приветствуется.

Ответ 1

Я считаю, что это ошибка в Chrome.

Ответ 2

ОБНОВЛЕНИЕ 2017-03-22: Повторяющиеся заголовки таблиц наконец-то реализованы в Chrome! (На самом деле, я думаю, что они были реализованы некоторое время назад.) Это означает, что вам, вероятно, больше не нужно это решение; просто поместите заголовки столбцов в тег <thead>, и все будет готово. Используйте приведенное ниже решение, только если:

  • вы столкнулись с ошибками остановки показа в реализации Chrome,
  • вам нужны "бонусные функции", или
  • вам нужно поддерживать какой-то странный браузер, который все еще не поддерживает повторяющиеся заголовки.

РЕШЕНИЕ (устарело)

Код ниже демонстрирует лучший метод, который я нашел для многостраничной печати таблиц. Он имеет следующие функции:

  • Заголовки столбцов повторяются на каждой странице
  • Не нужно беспокоиться о размере бумаги или о том, сколько строк будет fit--, браузер обрабатывает все автоматически
  • Разрывы страниц происходят только между строками
  • Границы ячейки всегда полностью закрыты
  • Если разрыв страницы происходит в верхней части таблицы, он не оставляет потерянных заголовков или заголовков столбцов без прикрепленных данных (проблема не ограничивается только Chrome)
  • Работает в Chrome! (и другие браузеры на основе Webkit, такие как Safari и Opera)

... и следующие известные ограничения:

  • Поддерживает только 1 <thead> (что, по всей видимости, самое большее, что вам разрешено иметь в любом случае)
  • Не поддерживает <tfoot> (хотя Chrome-совместимые нижние колонтитулы технически возможны)
  • Поддерживает только выравнивание по верху <caption>
  • Стол не может иметь верх или низ margin; чтобы добавить пробел над или под таблицей, вставьте пустой элемент div и установите для него нижнее поле
  • Любые значения размера CSS, которые влияют на высоту (включая 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 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>

КАК ЭТО РАБОТАЕТ (Если вам все равно, не читайте дальше; все, что вам нужно, находится выше.)

В ответ на запрос @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>

Ответ 3

теперь можно печатать в chrome с помощью jQuery.... пожалуйста, попробуйте этот код (извините, кто создатель этого кода до того, как я изменил), и мой английский язык не хорош: D hehehe)

            <!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>

Ответ 4

Это усовершенствование, которое пока недоступно в Webkit, Blink и Vivliostyle, а не в других более "ориентированных на печать форматах" (Firefox, IE).

Вы можете проверить проблему для Google Chrome с версии 4 здесь (6 лет и 45 версий назад!), где мы можем оценить ее владелец в последнее время (февраль 2016 года), который даже, кажется, работает над этим.

Некоторые разговоры также были проведены в W3, где мы можем оценить его полезность:

Так как повторение верхних и нижних колонтитулов таблицы на разрыв фрагментации, как правило, полезен, я предлагаю сделать нормативное требование и сказать, что UA должны повторять строки заголовка/нижнего колонтитула когда таблица охватывает разрыв.

Между тем коды JS и JQuery от @DoctorDestructo и @thefredzx были действительно полезны для моих пользователей, не использующих Firefox и IE (большинство из них).

Первый, кто должен знать о новой версии, включающей эту функцию, должен заметить ее здесь, многие из нас это оценят.

Ответ 5

Из моего тестирования в хромовой настройке 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>

Ответ 6

Примечание от 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; } }

чтобы отключить это правило браузера.

Ответ 7

для внутренних систем на базе браузера, я рекомендую пользователям использовать Firefox или IE, а для сайтов, предназначенных для публики, я думаю, что мы ничего не можем с этим поделать, если пользователи пользователей Chrome или браузеры с подобными ограничениями (опера также)