Como lidar com quebras de página ao imprimir uma tabela HTML grande

261

Eu tenho um projeto que requer a impressão de uma tabela HTML com muitas linhas.

Meu problema é a maneira como a tabela é impressa em várias páginas. Às vezes, ele corta uma linha pela metade, tornando-a ilegível porque a metade está na borda de uma página e o restante é impresso na parte superior da página seguinte.

A única solução plausível em que consigo pensar é usar DIVs empilhados em vez de uma tabela e forçar quebras de página, se necessário .. mas antes de passar por toda a mudança, pensei em perguntar aqui antes.

h3
fonte
28
Em uma tangente, pode valer a pena adicionar um <thead>à sua tabela com o seguinte css thead {display: table-header-group; }, para imprimir o cabeçalho da tabela em todas as páginas subseqüentes (útil para loooooongas tabelas de dados).
David diz que restabelece Monica

Respostas:

277
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Test</title>
<style type="text/css">
    table { page-break-inside:auto }
    tr    { page-break-inside:avoid; page-break-after:auto }
    thead { display:table-header-group }
    tfoot { display:table-footer-group }
</style>
</head>
<body>
    <table>
        <thead>
            <tr><th>heading</th></tr>
        </thead>
        <tfoot>
            <tr><td>notes</td></tr>
        </tfoot>
        <tbody>
        <tr>
            <td>x</td>
        </tr>
        <tr>
            <td>x</td>
        </tr>
        <!-- 500 more rows -->
        <tr>
            <td>x</td>
        </tr>
    </tbody>
    </table>
</body>
</html>
Sinan Ünür
fonte
18
Isso também falha nos navegadores WebKit (por exemplo, Safari e Chrome)
Michael Haren
5
Embora essa seja a maneira compatível com os padrões, o único navegador que atualmente implementa o padrão é o Opera. Observe que isso faz parte do css2 e, portanto, a falta de implementação provavelmente será um problema por algum tempo, porque aparentemente ninguém se importa.
Pkh
16
A especificação CSS 2.1 indica que os atributos de estilo de quebra de página são aplicados apenas a elementos em nível de bloco. O modo de exibição padrão para as linhas da tabela é a linha da tabela. Infelizmente, por padrão, nenhum elemento da tabela é um elemento no nível do bloco, incluindo a própria tabela.
Lsuarez #
2
@ SinanÜnür Não é um requisito, portanto você não pode confiar nele e, infelizmente, pelos meus testes, posso ver que o webkit viu "pode" e ignorou qualquer coisa além dele. Estranhamente, o IE tem um ótimo suporte para impressão de tabelas grandes. Nunca pensei que fosse cantar louvores em um determinado ponto.
Lsuarez #
6
Posso confirmar que isso NÃO funciona bem no Chrome ou em qualquer outro navegador da Webkit (por exemplo, Safari, Opera) - a menos que, por "funcione bem", você queira dizer "exclua todos os recursos considerados opcionais". Acho que o que a maioria das pessoas deseja é executar cabeçalhos e rodapés e tabelas que permitem apenas quebras de página entre linhas, nenhuma das quais é implementada no Webkit a partir de 13/11/2015.
DoctorDestructo
47

Nota: ao usar a quebra de página depois: sempre para a tag, ela criará uma quebra de página após o último bit da tabela, criando uma página totalmente em branco no final sempre! Para corrigir isso, basta alterá-lo para page-break-after: auto. Ele quebrará corretamente e não criará uma página em branco extra.

<html>
<head>
<style>
@media print
{
  table { page-break-after:auto }
  tr    { page-break-inside:avoid; page-break-after:auto }
  td    { page-break-inside:avoid; page-break-after:auto }
  thead { display:table-header-group }
  tfoot { display:table-footer-group }
}
</style>
</head>

<body>
....
</body>
</html>
Josh P
fonte
Funciona para mim no Chrome e é uma boa solução CSS simples.
21717 Ryan
1
Estou tentando a mesma solução, mas ela não quebra os dados da tabela e desaparece dados extras em vez de exibi-los na próxima página. Qualquer suposição?
Null Pointer
24

Expansão da solução Sinan Ünür:

<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Test</title>
<style type="text/css">
    table { page-break-inside:auto }
    div   { page-break-inside:avoid; } /* This is the key */
    thead { display:table-header-group }
    tfoot { display:table-footer-group }
</style>
</head>
<body>
    <table>
        <thead>
            <tr><th>heading</th></tr>
        </thead>
        <tfoot>
            <tr><td>notes</td></tr>
        </tfoot>
        <tr>
            <td><div>Long<br />cell<br />should'nt<br />be<br />cut</div></td>
        </tr>
        <tr>
            <td><div>Long<br />cell<br />should'nt<br />be<br />cut</div></td>
        </tr>
        <!-- 500 more rows -->
        <tr>
            <td>x</td>
        </tr>
    </tbody>
    </table>
</body>
</html>

Parece que page-break-inside:avoidem alguns navegadores é levado em consideração apenas para elementos de bloco, não para célula, tabela, linha nem bloco embutido.

Se você tentar display:blocka TRtag e usá- page-break-inside:avoidla, ela funciona, mas mexe com o layout da sua tabela.

vicenteherrera
fonte
2
Aqui está uma maneira fácil de adicionar os divs dinamicamente com jQuery:$(document).ready(function(){$("table tbody th, table tbody td").wrapInner("<div></div>");});
Chris Bloom
1
Agradecimentos a sinan ürün, vicenteherrera e Chrisbloom7. Eu apliquei a combinação de suas respostas e agora funciona!
Nurhak Kaya 3/08/16
Você pode tentar definir o CSS @media tr { display: block; }para Somente impressão, em vez de adicionar todos os <div>elementos estranhos . (Não testei, mas vale a pena olhar)
Stephen R
11

Nenhuma das respostas aqui funcionou para mim no Chrome. O AAverin no GitHub criou um Javascript útil para esse fim e funcionou para mim:

Basta adicionar os js ao seu código e adicionar a classe 'splitForPrint' à sua tabela, dividindo-a ordenadamente em várias páginas e adicionando o cabeçalho da tabela a cada página.

MDave
fonte
Você tem amostra de como aplicar isso? Eu tenho tentado atribuir minha tabela className como, splitForPrintmas no JS, em nenhum lugar foi necessária a referência do elemento usando o className splitForPrint. Apenas a parte onde var splitClassName = 'splitForPrint';mas é isso.
Compaq LE2202x
O voto foi negado porque o script ao qual você se vinculou não resolve o problema do OP sem considerável escolha e reconfiguração, e você não forneceu nenhum exemplo de como alguém poderia fazê-lo.
Chris Bloom
Funcionou como um encanto para mim, nenhuma das outras soluções funcionou. +1 Foi necessário adicionar um pouco de css para obter as quebras corretas .page-break {page-break-after: always; }
fhugas 01/02
Sim, adicionando .page-break {page-break-after: always; } ele salvou meu dia!
Milodky
7

Use estas propriedades CSS:

page-break-after

page-break-before 

Por exemplo:

<html>
<head>
<style>
@media print
{
table {page-break-after:always}
}
</style>
</head>

<body>
....
</body>
</html>

através da

marcgg
fonte
Não tenho certeza, você terá que verificar. Se não, separação de diferentes matrizes e separar as matrizes por um vazio div
marcgg
Você terá que aplicá-lo na linha da tabela ou até na célula, mas não na tabela, eu acho. Fora isso, deve funcionar.
181 Pekka
2
não funciona no chrome. É ignorado como se 13/6/2012 quando aplicado ao TR
ladieu 13/06/2012
5

Eu recentemente resolvi esse problema com uma boa solução.

CSS :

.avoidBreak { 
    border: 2px solid;
    page-break-inside:avoid;
}

JS :

function Print(){
    $(".tableToPrint td, .tableToPrint th").each(function(){ $(this).css("width",  $(this).width() + "px")  });
    $(".tableToPrint tr").wrap("<div class='avoidBreak'></div>");
    window.print();
}

Funciona como um encanto!

Wendel Tavares
fonte
2

Acabei seguindo a abordagem do @ vicenteherrera, com alguns ajustes (que são possivelmente específicos do bootstrap 3).

Basicamente; não podemos quebrar trs ou tds porque eles não são elementos em nível de bloco. Então, incorporamos divs em cada um e aplicamos nossas page-break-*regras contra o div. Em segundo lugar; adicionamos algum preenchimento à parte superior de cada uma dessas divs para compensar qualquer artefato de estilo.

<style>
    @media print {
        /* avoid cutting tr's in half */
        th div, td div {
            margin-top:-8px;
            padding-top:8px;
            page-break-inside:avoid;
        }
    }
</style>
<script>
    $(document).ready(function(){
        // Wrap each tr and td's content within a div
        // (todo: add logic so we only do this when printing)
        $("table tbody th, table tbody td").wrapInner("<div></div>");
    })
</script>

Os ajustes de margem e preenchimento foram necessários para compensar algum tipo de instabilidade que estava sendo introduzida (pelo meu palpite - a partir do bootstrap). Não tenho certeza se estou apresentando alguma solução nova das outras respostas a essa pergunta, mas acho que talvez isso ajude alguém.

Aaron
fonte
1

Enfrentei o mesmo problema e procurei em toda parte uma solução; finalmente, encontro algo que funcione para todos os navegadores.

html {
height: 0;
}

use este css ou em vez de css você pode ter este javascript

$("html").height(0);

Espero que isso funcione para você também.

Jay
fonte
0

Eu verifiquei muitas soluções e ninguém estava funcionando bem.

Então, eu tentei um pequeno truque e funciona:

tfoot com estilo: position: fixed; bottom: 0px; é colocado na parte inferior da última página, mas se o rodapé for muito alto, ele será sobreposto pelo conteúdo da tabela.

tfoot com only: display: table-footer-group; não se sobrepõe, mas não está na parte inferior da última página ...

Vamos colocar dois tfoot:

TFOOT.placer {
  display: table-footer-group;
  height: 130px;
}

TFOOT.contenter {
  display: table-footer-group;
  position: fixed;
  bottom: 0px;	
  height: 130px;
}
<TFOOT  class='placer'> 
  <TR>
    <TD>
      <!--  empty here
-->
    </TD>
  </TR>
</TFOOT>	
<TFOOT  class='contenter'> 
  <TR>
    <TD>
      your long text or high image here
    </TD>
  </TR>
</TFOOT>

Uma reserva é colocada em páginas que não são as últimas, a segunda colocação no rodapé da acumulação.

Zenon K.
fonte
-1

Tentei todas as sugestões fornecidas acima e encontrei uma solução simples e funcional para vários navegadores para esse problema. Não há estilos ou quebra de página necessários para esta solução. Para a solução, o formato da tabela deve ser como:

<table>
    <thead>  <!-- there should be <thead> tag-->
        <td>Heading</td> <!--//inside <thead> should be <td> it should not be <th>-->
    </thead>
    <tbody><!---<tbody>also must-->
        <tr>
            <td>data</td>
        </tr>
        <!--100 more rows-->
    </tbody>
</table>

Formato acima testado e funcionando em navegadores cruzados

Ananth Doss
fonte
-2

Bem, pessoal ... A maioria das soluções aqui em cima não funcionou. Então é assim que as coisas funcionaram para mim ..

HTML

<table>
  <thead>
   <tr>
     <th style="border:none;height:26px;"></th>
     <th style="border:none;height:26px;"></th>
     .
     .
   </tr>
   <tr>
     <th style="border:1px solid black">ABC</th>
     <th style="border:1px solid black">ABC</th>
     .
     .
   <tr>
  </thead>
<tbody>

    //YOUR CODE

</tbody>
</table>

O primeiro conjunto de cabeçotes é usado como um fictício, para que não haja uma borda superior ausente no segundo cabeçalho (ou seja, cabeçalho original) durante a quebra de página.

Aneesh
fonte
-3

A resposta aceita não funcionou para mim em todos os navegadores, mas o css a seguir funcionou para mim:

tr    
{ 
  display: table-row-group;
  page-break-inside:avoid; 
  page-break-after:auto;
}

A estrutura html era:

<table>
  <thead>
    <tr></tr>
  </thead>
  <tbody>
    <tr></tr>
    <tr></tr>
    ...
  </tbody>
</table>

No meu caso, houve alguns problemas adicionais com o thead tr, mas isso resolveu o problema original de impedir a quebra das linhas da tabela.

Por causa dos problemas de cabeçalho, acabei tendo:

#theTable td *
{
  page-break-inside:avoid;
}

Isso não impediu a quebra de linhas; apenas o conteúdo de cada célula.

David Moeller
fonte