SitePoint Sponsor

User Tag List

Results 1 to 7 of 7
  1. #1
    SitePoint Enthusiast
    Join Date
    Sep 2010
    Location
    IA, USA
    Posts
    25
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Orphaned table headers when printing from Firefox

    This is one of many problems I've been having with Firefox since I started working on the printouts for my current project.

    What's happening is that, when the dynamic content above a table grows to the point that there is only enough room left on the page for the table's header row, instead of bumping the whole table to the next page like it should, Firefox prints an orphaned header row at the bottom of the page.

    The following example assumes 8.5"x11" paper with top and bottom margins of 0.5". (Note that the actual number you have to enter in FF's Page Setup dialog in order to actually get 0.5" margins may not be 0.5. For me, 0.329 did the trick):

    Code HTML4Strict:
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
    <style type="text/css">
    	body {
    		margin: 0;
    		padding: 0;
    		font-family: Arial, Helvetica, sans-serif;
    		line-height: 18px;
    		font-size: 14px;
    	}
     
    	table {
    		width: 700px;
    		margin: 0 auto 0 auto;
    		table-layout: fixed;
    		border-spacing: 0;
    	}
     
    	th, td {
    		padding: 0;
    		border: solid black;
    		border-width: 0 1px 1px 0;
    	}
     
    	th:first-child, td:first-child {
    		border-left-width: 1px;
    	}
     
    	th {
    		border-top-width: 1px;
    	}
    </style>
    </head>
    <body>
     
    <div style="height: 920px;">
    <!--resize this div to change page break location-->
    </div>
     
    <table>
    	<thead>
    		<tr>
    			<th>
    				Header
    			</th>
    			<th>
    				Header
    			</th>
    		</tr>
    	</thead>
    	<tfoot>
    		<tr>
    			<td>
    				Footer
    			</td>
    			<td>
    				Footer
    			</td>
    		</tr>
    	</tfoot>
    	<tbody>
    		<tr>
    			<td>
    				Data
    			</td>
    			<td>
    				Data
    			</td>
    		</tr>
    		<tr>
    			<td>
    				Data
    			</td>
    			<td>
    				Data
    			</td>
    		</tr>
    		<tr>
    			<td>
    				Data
    			</td>
    			<td>
    				Data
    			</td>
    		</tr>
    	</tbody>
    </table>
     
    </body>
    </html>

    The only way I've found to deal with this problem is to create an inline-block element that is the same height as the header row and the first data row, and layer it behind the table using negative margins, like so:

    Code HTML4Strict:
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
    <style type="text/css">
    	body {
    		margin: 0;
    		padding: 0;
    		font-family: Arial, Helvetica, sans-serif;
    		line-height: 18px;
    		font-size: 14px;
    	}
     
    	table {
    		width: 700px;
    		margin: 0 auto 0 auto;
    		table-layout: fixed;
    		border-spacing: 0;
    	}
     
    	th, td {
    		padding: 0;
    		border: solid black;
    		border-width: 0 1px 1px 0;
    	}
     
    	th:first-child, td:first-child {
    		border-left-width: 1px;
    	}
     
    	th {
    		border-top-width: 1px;
    	}
    </style>
    </head>
    <body>
     
    <div style="height: 920px;">
    <!--resize this div to change page break location-->
    </div>
     
    <div style="display: inline-block; height: 39px;">
    </div>
    <div style="margin-bottom: -39px;">
    </div>
     
    <table>
    	<thead>
    		<tr>
    			<th>
    				Header
    			</th>
    			<th>
    				Header
    			</th>
    		</tr>
    	</thead>
    	<tfoot>
    		<tr>
    			<td>
    				Footer
    			</td>
    			<td>
    				Footer
    			</td>
    		</tr>
    	</tfoot>
    	<tbody>
    		<tr>
    			<td>
    				Data
    			</td>
    			<td>
    				Data
    			</td>
    		</tr>
    		<tr>
    			<td>
    				Data
    			</td>
    			<td>
    				Data
    			</td>
    		</tr>
    		<tr>
    			<td>
    				Data
    			</td>
    			<td>
    				Data
    			</td>
    		</tr>
    	</tbody>
    </table>
     
    </body>
    </html>

    This solution works ok, but I was wondering if anyone had come up with one that doesn't require extra markup, and/or adapts automatically to changes in the header and data row heights. I would prefer to avoid javascript, if possible.

  2. #2
    Ripe Tomatos silver trophybronze trophy Rayzur's Avatar
    Join Date
    Jun 2007
    Location
    Texas
    Posts
    4,174
    Mentioned
    4 Post(s)
    Tagged
    0 Thread(s)
    Hi,
    I have never really spent much time troubleshooting print problems so I thought I would take a look at it.

    Your inline-block dummy div does seem to work fine for me in FF too. When using it I changed the spacer div height to 880px and FF moved the entire table to the 2nd print page. But then IE8 broke the table and continued it on the 2nd page with another header (not orphaned though).

    What do you make of IE's behavior? Is this an undefined area with the specs where the UA can do as it pleases.

  3. #3
    The CSS Clinic is open silver trophybronze trophy
    Paul O'B's Avatar
    Join Date
    Jan 2003
    Location
    Hampshire UK
    Posts
    40,281
    Mentioned
    179 Post(s)
    Tagged
    6 Thread(s)
    Hi,

    The inline-block isn't working for me in Firefox 3.6 as I still get the header at the bottom of the page by itself depending on what dimensions I use.

    I'm also not seeing just the header but the header and the footer both overlapped on top of each other.

    Thead and tfoot elements should be printed on each page when a table spills over a boundary and Firefox is obviously having trouble with this.

    I had limited success using a caption element in the table and applying a height of 30px to it which seemed to work better than the inline-block method but did depend on data again and wasn't very reliable.

    The only other fix that partially worked was setting the table to an inline table.

    Code:
    table {
        display:inline-table
    }

    That seemed to work well for small tables but if the table was bigger than the page height the footer seemed to be cut off.

    Printing has always been the most troublesome part of CSS and not much works consistently anywhere.

  4. #4
    SitePoint Enthusiast
    Join Date
    Sep 2010
    Location
    IA, USA
    Posts
    25
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Rayzur View Post
    Your inline-block dummy div does seem to work fine for me in FF too. When using it I changed the spacer div height to 880px and FF moved the entire table to the 2nd print page. But then IE8 broke the table and continued it on the 2nd page with another header (not orphaned though).

    What do you make of IE's behavior? Is this an undefined area with the specs where the UA can do as it pleases.
    Maybe your margin or header/footer settings in IE8 aren't leaving enough printable area on the page to fit a block that is 880px tall. That would force the browser to crop the inline-block div rather than bumping it to the next page (and taking the table with it). Removing any headers or footers and setting your margins to 0.5" in IE8's Page Setup should give you 960px of vertical space to work with, which would allow the 880px inline-block div to be bumped instead of cropped.

    As for the specs, I've never really looked into them that deeply, but I suspect that there is a lot more gray area for paged media than for continuous.

    Quote Originally Posted by Paul O'B View Post
    The inline-block isn't working for me in Firefox 3.6 as I still get the header at the bottom of the page by itself depending on what dimensions I use.
    What do you mean by "changing dimensions"? Any change in the vertical dimension (height) of the header row or first data row must be accompanied by a corresponding change in the height of the inline-block div. The formula for calculating the height of the inline-block div is as follows:

    header row height + first data row height + 3px (to account for borders)

    If you do not zero out the cell padding as I did in my example, then you must include it in the calculation. Also, the negative margin that positions the inline-block div behind the table must always be equal to the height of the div.

    Note that the negative margin is NOT applied to the inline-block div itself, but to a separate div placed directly below it. Applying the negative margin to the inline-block div itself will cause it to be cropped by the page break instead of bumped to the next page along with the table.

    Does my code work for you if you copy it exactly? If not, then I must be wrong about inline-blocks being unbreakable, which is going to cause me more problems than just orphaned headers.

    Quote Originally Posted by Paul O'B View Post
    I had limited success using a caption element in the table and applying a height of 30px to it which seemed to work better than the inline-block method but did depend on data again and wasn't very reliable.
    If I can get this to work, it would at least allow me to avoid throwing in extra divs that have no obvious purpose.

    Quote Originally Posted by Paul O'B View Post
    The only other fix that partially worked was setting the table to an inline table. That seemed to work well for small tables but if the table was bigger than the page height the footer seemed to be cut off.
    In my testing, inline-table works similarly to inline-block in that it makes the whole element unbreakable. Obviously, any unbreakable element that is larger than the printable area is going to get cut off.

    One interesting thing I've discovered is that Firefox does seem to be smart enough to prevent a table footer from being widowed (i.e. separated from the last data row by a pagebreak). I'm sure table footers are used much less frequently than table headers, so it's strange that they work correctly while headers don't.

    Quote Originally Posted by Paul O'B View Post
    Printing has always been the most troublesome part of CSS and not much works consistently anywhere.
    The thing that's been troubling me since I started working on printing is how lopsided the buggyness has been in IE's favor. It's really beginning to make me question my worldview. Maybe IE9's printing will restore the proper balance to the cosmos by being a total disaster.

  5. #5
    The CSS Clinic is open silver trophybronze trophy
    Paul O'B's Avatar
    Join Date
    Jan 2003
    Location
    Hampshire UK
    Posts
    40,281
    Mentioned
    179 Post(s)
    Tagged
    6 Thread(s)
    Quote Originally Posted by discarnateEntity View Post
    What do you mean by "changing dimensions"? .
    I had to change the dimensions of the other element above the table (not the inline-block) because on my printer I get about 5 rows of the table on the first page.

    I just increased this value until I was left with the header on one page.
    Code:
    <div style="height: 920px;">
    <!--resize this div to change page break location-->
    </div>
    I didn't touch anything else.

    Did you notice that the header and footer are on top of each other also?

    The inline-table seemed to be the best of the bunch but I don't hold out much hope of finding a perfect solution as I tried almost everything.

  6. #6
    SitePoint Enthusiast
    Join Date
    Sep 2010
    Location
    IA, USA
    Posts
    25
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Paul O'B,

    I figured out why my example code wasn't working...

    There are two reasons, actually. First, the inline-block div needs to have content. For some reason, both FF and IE will add a small bottom margin to an inline-block element if it has nothing in it, which was preventing the div from aligning perfectly with the table. Putting a <br /> or an &nbsp; inside the inline-block div will fix this problem.

    Second, the formula for calculating the height of the inline-block div and the negative margin needs to have the height of the footer added to it. This will prevent any weird overlapping footer issues.

    Here is a revised example that should work perfectly in both FF and IE (as before, the spacer div will probably have to be enlarged to make the table overflow your A4 paper ):
    Code:
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
    <style type="text/css">
    	body {
    		margin: 0;
    		padding: 0;
    		font-family: Arial, Helvetica, sans-serif;
    		line-height: 18px;
    		font-size: 14px;
    	}
    	
    	table {
    		width: 700px;
    		margin: 0 auto 0 auto;
    		table-layout: fixed;
    		border-spacing: 0;
    	}
    
    	th, td {
    		padding: 0;
    		border: solid black;
    		border-width: 0 1px 1px 0;
    	}
    
    	th:first-child, td:first-child {
    		border-left-width: 1px;
    	}
    
    	th {
    		border-top-width: 1px;
    	}
    </style>
    </head>
    <body>
    
    <div style="height: 900px;">
    <!--resize this div to change page break location-->
    </div>
    
    <div style="display: inline-block; height: 58px;">
    	<br />
    </div>
    <div style="margin-bottom: -58px;">
    </div>
    
    <table>
    	<thead>
    		<tr>
    			<th>
    				Header
    			</th>
    			<th>
    				Header
    			</th>
    		</tr>
    	</thead>
    	<tfoot>
    		<tr>
    			<td>
    				Footer
    			</td>
    			<td>
    				Footer
    			</td>
    		</tr>
    	</tfoot>
    	<tbody>
    		<tr>
    			<td>
    				Data
    			</td>
    			<td>
    				Data
    			</td>
    		</tr>
    		<tr>
    			<td>
    				Data
    			</td>
    			<td>
    				Data
    			</td>
    		</tr>
    		<tr>
    			<td>
    				Data
    			</td>
    			<td>
    				Data
    			</td>
    		</tr>
    	</tbody>
    </table>
    
    </body>
    </html>

  7. #7
    The CSS Clinic is open silver trophybronze trophy
    Paul O'B's Avatar
    Join Date
    Jan 2003
    Location
    Hampshire UK
    Posts
    40,281
    Mentioned
    179 Post(s)
    Tagged
    6 Thread(s)
    Yes that seems to have done the trick

    It's a bit fragile and relies on the dimensions etc but I suppose for a one-off situation it could be a solution.

    I had another play around and couldn't seem to find anything better.


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •