Creating page headers and footers using CSS for print

90,050

Solution 1

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)

Solution 2

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)

Solution 3

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>
Share:
90,050
Naftuli Kay
Author by

Naftuli Kay

Updated on September 14, 2021

Comments

  • Naftuli Kay
    Naftuli Kay almost 3 years

    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?

  • Naftuli Kay
    Naftuli Kay over 12 years
    Wow, wish I would have known this sooner, I've been fighting background-image to do it the less complete way. Thanks so much!
  • Primoz Rome
    Primoz Rome about 11 years
    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.
  • Jaro
    Jaro about 11 years
    Does it works in Firefox or Chrome? I tried it both, but it doesn't work for me :/
  • Adam
    Adam about 11 years
    @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.
  • Dai
    Dai over 4 years
    As of January 2020, the content: element(...) feature is only supported by Firefox - and not Chrome/Webkit/Edge.
  • Dai
    Dai over 4 years
    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.
  • Andre Aus B
    Andre Aus B over 4 years
    THX for that! Adding the footer element before the other elements helped to solve my problem.
  • ˈvɔlə
    ˈvɔlə over 4 years
    Works using pagedjs.org in all major browsers. Give it a try!
  • John T
    John T over 3 years
    This works great - not clear though on where the .page-number item comes into play.
  • zinon
    zinon almost 3 years
    Also, do not have display:block; in body or @page otherwise running() won't work.
  • WBT
    WBT almost 3 years
    In Chrome & Firefox at least, this is now overlapping page content except for the initial header.
  • DerpyNerd
    DerpyNerd about 2 years
    @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