How to insert repeatable footer / header blocks on pages of HTML to PDF report

Describe in details and provide an example of report with structure:

page

  • header
  • content
  • footer + page number

page

  • header
  • content
  • footer + page number
4 Likes

I figured it out myself.
I had to use running headers & footers (found it in the flying-saucer documentation).
For others who might find it useful:

<html>
<head>
<style>
div.header {
    display: block; text-align: center; 
    position: running(header);
}
div.footer {
    display: block; text-align: center;
    position: running(footer);
}
@page {
    @top-center { content: element(header) }
}
@page { 
    @bottom-center { content: element(footer) }
}
</style>
</head>
<body>
    <div class='header'>Header</div>
    <div class='footer'>Footer</div>
</body>
</html>

Hi,

Thanks for the useful info!
I played with html templates and flying-saucer and I managed to build a html report with fixed header, footer repeatable on each page (like in your example).
In the report I have a standard table with its own tableheader, which I managed to make it repeat on each page by adding:

-fs-table-paginate: paginate;

in the css for that table.
Everything is fine except that if the table is larger and does not fit in 1 page (99% of the cases) the table overlaps with the footer and the header of the next page. I’ve tried adding padding like in your example and padding in the #header and #footer div but without success. The only place where padding works is on @page, but if I need a custom header or footer it’s not working.
I’m sure I am missing something. Do you have some examples working with this (I think basic) request?

Thank you.

TL;DR You can find demo project and properly formatted answer here: GitHub - cuba-labs/reports-pdf-page-settings

Basic principles of HTML to PDF formatting in YARG / CUBA reporting:

Useful resources:

Let’s imagine that we want to create a report with landscape orientation, page numbers, fixed page header and footer on each page:

We will start with HTML structure:

<body> 
  <h1>Clients report</h1> 
  <!-- Custom HTML header --> 
  <div id="header"> 
    <h2>Annual Report of our Company</h2> 
  </div>  <!-- Custom HTML footer --> 
  <div id="footer"> 
    <h2>Address: William Road</h2> 
    <span class="custom-footer-page-number">Number: </span> 
  </div> 

  <#assign clients = Root.bands.Clients /> 

  <#list clients as client> 
  <!-- New page for each client  --> 
  <div class="custom-page-start" style="page-break-before: always;"> 
    <h2>Client</h2> 
    <p>Name: ${client.fields.title}</p> 
    <p>Summary: ${client.fields.summary}</p> 
  </div> 
  </#list>
</body>

Here we define header and footer blocks that will be printed on each PDF page. Also we use special <i>page-break-before: always</i> CSS property. It will generate page break before each client info block.
As you can see we use FreeMarker statements to insert data to our template. See complete FreeMarker reference here: Apache FreeMarker Manual

We will use the following CSS code to tune our PDF page representation:

body { 
  font: 12pt Georgia, "Times New Roman", Times, serif; 
  line-height: 1.3;}
  @page { 
    /* switch to landscape */ 
   size: landscape; 
   /* set page margins */ 
   margin: 0.5cm; 
   /* Default footers */ 
   @bottom-left { 
     content: "Department of Strategy"; 
   } 
   @bottom-right { 
     content: counter(page) " of " counter(pages); 
  }
}

And this CSS code to set header/footer positions:

/* footer, header - position: fixed */
#header { 
  position: fixed; 
  width: 100%; 
  top: 0; 
  left: 0; 
  right: 0;
}
#footer { 
  position: fixed; 
  width: 100%; 
  bottom: 0; 
  left: 0;
  right: 0;
}

After that we need to fix paddings of main content to prevent content and header/footer overlapping:

/* Fix overflow of headers and content */
body {
    padding-top: 50px;
}
.custom-page-start {
    margin-top: 50px;
}

What if we want to insert page number to custom position? That’s it:

.custom-footer-page-number:after {
  content: counter(page);
}

Full report template and sample project are hosted on GitHub: GitHub - cuba-labs/reports-pdf-page-settings
If you want to insert images to your PDF files, see our existing documentation: HTML Template - CUBA Platform. Report Generator See Embedded pictures section.

f2d1d0c589b6ecf993be9302417576ae

2 Likes

Thank you for the snippet! It is really useful!

Test4.html (6.2 KB)
image
please see attached file i have added some content in you format but when i print it in second Page content overlapping my footer and header
please suggest any solution

As described above, you can use position: running(footer) for footer on each page without overlapping.

For instance:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>Invoice</title>
  <style type="text/css">
    body {
      font: 12pt Georgia, "Times New Roman", Times, serif;
      line-height: 1.3;
    }

    div.header {
      display: block;
      text-align: center;
      position: running(header);
    }

    div.footer {
      display: block;
      text-align: center;
      position: running(footer);
    }

    @page {
        @top-center {
            content: element(header);
        }
    }
    @page {
        @bottom-center {
            content: element(footer);
        }
    }
  </style>
</head>
<body>
  <h1>Clients report</h1>

  <!-- Custom HTML header -->
  <div class="header">
      Annual Report of our Company
  </div>

  <!-- Custom HTML footer -->
  <div class="footer">
    Address: William Road
  </div>

  <#assign clients = Root.bands.Clients />

  <#list clients as client>
  <div class="custom-page-start">
    <h2>Client</h2>

    <p>Name: ${client.fields.title}</p>
    <p>Summary: ${client.fields.summary}</p>
  </div>
  </#list>
</body>
</html>

Hi, I have tried as described but still
Problem is there. :frowning:
Screen

Try this combinative solution instead which uses both thead tbody tfoot tags and position: fixed; technique, it help me out.

1 Like

hello why i got zero when i print preview?image image how to count this one? how to fix this?