csshtml-tableprint-css

Table with print media css is breaking at an offset position


I've got a web page with a few elements at the top and the a long table of data rows and I'm trying to fix the css so that it will do page breaks appropriately.

This is more complicated than just using the page-break-* rules, because something is offsetting the position where the table is getting its page breaks.

The screenshot below is from my print preview window. The big fat red border is a print css rule I added to the tbody so that I could see where it started and ended. Notice that on page 2 of the preview that the table shows a page break between the Fredrick and Gerardo rows. So, it IS breaking the table between rows, as it should, it's just that it is breaking them between the wrong rows... or what it really looks like is that when it is counting to see when it hits the edge of the page, it is starting from the wrong place.

Here's what I mean by that: I've got a few elements above the table (the title of the report, a few boxes that show some filter values, and a number of records count). If I use the Chrome inspector to delete those elements from the page before trying to print, then the row-level page breaks that Chrome is calculating match up perfectly with the page and everything prints properly.

So, it appears that Chrome is calculating the high of the table rows that will fit on the entire page, but ignoring the elements above the table during that calculation. But when actually printing, those above-elements are still included and therefore it doesn't break the table at the correct row.

Does that make sense?

How do I fix this?

@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 }

    table.listing tbody {
        border: 15px solid red;
    }

    table.listing tbody.display td {
        color: red;
    }
}

landscape printing showing breaking at a weird offset

portrait printing showing that weird offset cuts a row in the middle


Solution

  • I think you have relatively positioned table and it has been shifted down by height equal to menu bar height. For example, put below code in separate html file and try to print it. You'll see similar effect.

    <!DOCTYPE html>
    
    <head>
    
      <style>
        :root {
          --menu-height: 200px;
        }
    
        @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 }
    
         table.listing tbody {
            border: 15px solid red;
         }
    
         table.listing tbody.display td {
            color: red;
         }
       }
    
        td,
        th {
          border: 1px solid gray;
          height: 2cm;
        }
    
        table {
          position: relative;      /* <-- position shifted table */
          top: var(--menu-height); /* <-- shifted down by menu height */
    
          border-collapse: collapse;
          border: 10px solid red
        }
    
        .menu-bar {
          position: absolute;      /* <-- floating menubar */
          top: 0px;
          width: 300px;
          height: var(--menu-height);
          background-color: bisque;
    
        }
      </style>
    </head>
    
    <body>
      <div class="menu-bar">
        <h5>Herd Report</h5>
        <p>mountain goat</p>
      </div>
    
    
      <table>
        <tr>
          <th>asd</th>
          <th>bbbb</th>
          <th>bcccc</th>
          <th>dddd</th>
          <th>eee</th>
          <th>ff ff</th>
          <th>ggg </th>
          <th>hhh h</th>
        </tr>
        <tr><td>1</td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
        <tr><td>2</td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
        <tr><td>3</td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
        <tr><td>4</td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
        <tr><td>5</td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
        <tr><td>6</td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
        <tr><td>7</td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
        <tr><td>8</td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
        <tr><td>9</td><td></td><td></td><td></td><td></td><td></td><td></td><td>c</td></tr>
        <tr><td>0</td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
        <tr><td>11</td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
        <tr><td>12</td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
        <tr><td>13</td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
        <tr><td>14</td><td>5</td><td></td><td></td><td></td><td></td><td></td><td></td>
        </tr>
      </table>
    </body>
    
    </html>
    

    enter image description here

    In above example the table is positioned relative. This is what the CSS standard say about position:relative:

    relative
    The element is positioned according to the normal flow of the document, and then offset relative to itself based on the values of top, right, bottom, and left. The offset does not affect the position of any other elements; thus, the space given for the element in the page layout is the same as if position were static.

    For more info refer: https://developer.mozilla.org/en-US/docs/Web/CSS/position

    If you play with the demo in the documentation, you'll notice that position relative reserves the spot and space on the page but the element is moved relative to that spot. So while printing the table browser considers element's static position, at top left in our case, and splits rows accordingly. But due to relative positioning table is shifted down and breaks at unwanted spots.
    To fix the positioning you need to add following CSS rules at the end of style sheet.

        @media print {
         .menu-bar{
           position: static;
         }
         table{
           position: static;
         }
       }
    

    What we are saying here is if media is print then position menubar and table statically.
    You might have a lot and complex styling in your project but you may need to style the entire document separately for print media.