54

I'm creating a PDF using Flying Saucer (which dumps out CSS/HTML to iText to a PDF) and I'm trying to use CSS3 to apply an image header and footer to each page.

I'd essentially like to put this div in the top left of each page:

<div id="pageHeader">
    <img src="..." width="250" height="25"/>
</div>

My CSS looks somewhat like this:

@page {
    size: 8.5in 11in;
    margin: 0.5in;

    @top-left {
        content: "Hello";
    }
}

Is there a way for me to put this div in the content?

venimus
  • 5,907
  • 2
  • 28
  • 38
Naftuli Kay
  • 87,710
  • 93
  • 269
  • 411

3 Answers3

44

Putting an element to the top of each page:

@page {
  @top-center {
    content: element(pageHeader);
  }
}
#pageHeader{
  position: running(pageHeader);
}

See http://www.w3.org/TR/css3-gcpm/#running-elements (works in Flying Saucer)

Adam
  • 5,045
  • 1
  • 25
  • 31
  • Wow, wish I would have known this sooner, I've been fighting `background-image` to do it the less complete way. Thanks so much! – Naftuli Kay Mar 16 '12 at 18:44
  • 1
    I am trying to adopt this but for some reason in Chrome the header is only printed on first page, and the footer on last page only. In Firefox this is completely broken. – Primoz Rome May 26 '13 at 14:41
  • 4
    Does it works in Firefox or Chrome? I tried it both, but it doesn't work for me :/ – Jaro May 29 '13 at 08:59
  • 5
    @Jaro this question is about generating PDF using Flying Saucer. If you want the same in Firefox/Chrome, you will have a much higher chance to recieve an answer if you ask a new question. – Adam May 29 '13 at 13:29
  • 1
    Works using https://www.pagedjs.org/ in all major browsers. Give it a try! – ˈvɔlə Mar 25 '20 at 21:18
10

To include both header and footer on pages (elaborating on excellent answer from @Adam):

<style>
@page {

    margin: 100px 25px;
    size: letter portrait;

    @top-left {
        content: element(pageHeader);
    }

    @bottom-left {
        content: element(pageFooter);
    }
}

#pageHeader{
    position: running(pageHeader);
}

#pageFooter{
    position: running(pageFooter);
}

</style>
<body>
    <header id="pageHeader">something from above</header>
    <footer id="pageFooter">lurking below</footer>

    <div>meaningful rambling...</div>
</body>

NOTE: In order for footer to repeat on every page it may be necessary to define it BEFORE other body content (for multi-page content)

zeffren
  • 101
  • 1
  • 3
  • 5
    As of January 2020, the `content: element(...)` feature is only supported by Firefox - and not Chrome/Webkit/Edge. – Dai Jan 25 '20 at 03:11
  • THX for that! Adding the footer element before the other elements helped to solve my problem. – Andre Aus B Mar 12 '20 at 09:44
  • Also, do not have `display:block;` in `body` or `@page` otherwise `running()` won't work. – zinon Jul 22 '21 at 08:43
8

I spent a lot of time to get this working on modern Chrome, Firefox and Safari. I use this to create a PDF from HTML. You will get header and footer fixed to each page without overlapping the page content. Try it:

CSS

<style>
  @page {
    margin: 10mm;
  }

  body {
    font: 9pt sans-serif;
    line-height: 1.3;

    /* Avoid fixed header and footer to overlap page content */
    margin-top: 100px;
    margin-bottom: 50px;
  }

  #header {
    position: fixed;
    top: 0;
    width: 100%;
    height: 100px;
    /* For testing */
    background: yellow; 
    opacity: 0.5;
  }

  #footer {
    position: fixed;
    bottom: 0;
    width: 100%;
    height: 50px;
    font-size: 6pt;
    color: #777;
    /* For testing */
    background: red; 
    opacity: 0.5;
  }

  /* Print progressive page numbers */
  .page-number:before {
    /* counter-increment: page; */
    content: "Page: " counter(page);
  }

</style>

HTML

<body>

  <header id="header">Header</header>

  <footer id="footer">footer</footer>

  <div id="content">
    Here your long long content...
    <p style="page-break-inside: avoid;">This text will not be broken between the pages</p>
  </div>

</body>
Fred K
  • 13,249
  • 14
  • 78
  • 103
  • Oh wow, this actually works great! I didn't expect Chrome to reprint `position: fixed;` elements in each printed page - but it does! :D Unfortunately page numbering won't work but I don't need page-numbering what I'm working on right now. – Dai Jan 25 '20 at 03:15
  • This works great - not clear though on where the .page-number item comes into play. – John T Mar 15 '21 at 14:24
  • 4
    In Chrome & Firefox at least, this is now overlapping page content except for the initial header. – WBT Sep 13 '21 at 19:42
  • @WBT is right, If it was working, it doesn't seem to work now. I've even tried setting the `z-index` to max (2147483647) and `top`, `left` and `right` to negative the margin of `@page`. They must have explicitly prevented us from editing headers and footers... crying shame – DerpyNerd May 07 '22 at 20:51