Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] Header and Footer Templates don't work when generating a PDF #14441

Closed
DaveNatalieTripArc opened this issue May 25, 2022 · 8 comments
Closed

Comments

@DaveNatalieTripArc
Copy link

Context:

  • Playwright Version: 1.22.0
  • Operating System: Windows 11
  • .NET version: .NET 6
  • Browser: Chromium

Code Snippet

using System.Threading.Tasks;
using Microsoft.Playwright;

class Program
{
    public static async Task Main()
    {
          using var playwright = await Playwright.CreateAsync();
          await using var browser = await playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions()
           {
               Headless = true
           });
           
           string url = "https://en.wikipedia.org/wiki/Microsoft";
           var page = await browser.NewPageAsync();
           await page.GotoAsync(url, new PageGotoOptions()
           {
                WaitUntil = WaitUntilState.NetworkIdle
           });

           var pdfOptions = new PagePdfOptions()
           {
                DisplayHeaderFooter = true,
                HeaderTemplate = "<span style=\"font-size: 20px;color:#000000;\">HEADER</span>",
                FooterTemplate = "<span style=\"font-size: 20px;color:#000000;\">FOOTER</span>",
                PrintBackground = true,
                Path = "file.pdf"
           };
          await page.PdfAsync(pdfOptions);
    }
}

Describe the bug

The header and footer are not visible in the generated document. I've tried including HTML tags in the template, and all kinds of style teqniques, but I have never been able to get the header and footer to display for any webpage.

@mxschmitt mxschmitt transferred this issue from microsoft/playwright-dotnet May 27, 2022
@crackalak
Copy link

crackalak commented Jun 13, 2022

@DaveNatalieTripArc margins are required to add the header and footer content, something like this should work:

var pdfOptions = new PagePdfOptions()
{
    Margin = new() { Top = "40px", Bottom = "40px" },
    DisplayHeaderFooter = true,
    HeaderTemplate = "<span style=\"font-size: 5pt;color:#000000;\">HEADER</span>",
    FooterTemplate = "<span style=\"font-size: 5pt;color:#000000;\">FOOTER</span>",
    PrintBackground = true,
    Path = "file.pdf"
};

@DaveNatalieTripArc
Copy link
Author

This now works for most urls (including the wikipedia page I used above), but I was still having issues.

Upon further inspection, I noticed this in a style tag of the page.

<style>
    @page {
        size: letter; 
        margin: 5mm 0mm;
    }
    @page:first {
        margin: 0;
    }
</style>

Removing this code allowed the header and footer to be displayed.

@DaveNatalieTripArc
Copy link
Author

Is it possible, using Playwright, to avoid showing the header and footer on the first page?

I tried using default margins, and overriding them with CSS

//Pdf Options
PreferCSSPageSize = true,
Margin = new Margin()
{
    Top = "5mm",
    Bottom = "20mm"
},

//CSS                    
@page:first {
   margin-top: 0mm;
   margin-bottom: 0mm;
 }

But doing so will prevent the header and footer from showing on all pages. If I comment out PreferCSSPageSize, I still don't get the header and footer, and the margins for my whole document are off. (Content prints to the bottom pf the page without respect for margin).

Oddly enough, I can partially accomplish this with the header only. Removing margin-bottom: 0mm; from the CSS will hide the header on the first page, and all subsequent pages will have the proper default margin. I have not, however, found a way to also hide the footer from the first page without breaking the rest of the document.

I also tried adding a class to the footer template <div class=\"pdf-footer\>, but the CSS for the page is unable to target this div. I even tried adding a style tag to the footer template, but I am unable to hide the footer this way.

@akashlimbani
Copy link

How I can add it center of footer ?

@leducvin
Copy link

leducvin commented Sep 27, 2022

If it can help anyone, here are my findings about the header and footer template. Some of it is apparently undocumented.

I used the following documentation: https://playwright.dev/python/docs/api/class-page#page-pdf

  • You do need some margins defined. Either define these using the margin argument, or set prefer_css_page_size=True with margins defined in the @page CSS rule (I did the latter).
  • Header and footer are displayed initially with 0px font size. If you zoom in on your PDF you might be able to see them. You have to use CSS or element style to set a bigger font size.
  • The header and footer templates have to be completely self-contained. That means you can't link to external CSS file or external images. For instance, you can include all the necessary CSS inside <head><style></style></head>. SVG images can be used by directly including the SVG code. Images can be used by using base64 encoding.
  • The header and footer are impervious to any CSS used in the rest of the document.
  • The CSS style applied to footer "bleeds" into the header. If you set all your rules in the footer template only, they will be applied in the header template too.
  • The header and footer do not respect the margins set using the margin argument or the margins set using CSS @page. You have to set the margins in the CSS included in the templates itself. I found that to center the header/footer properly, you can specify for example margin-left: 0.5in; and width: calc(100% - 1in);, which should work when your document's body already has 0.5 inch margins left and right.

So, I would say, header and footer do work when generating PDF, but the documentation misses out on a lot of stuff and they are not easy to get to work properly.

Here is how I went about the problem. I used the python API. Also, I used the Jinja project to template the header and footer templates.

For example, something along the lines of:

header_template.html

<!DOCTYPE html>
<html lang="fr-CA">
  <head>
    <meta charset="utf-8">
    <!-- Note: CSS is applied from the footer.html template. -->
  </head>
  <body>
    <div class="htmlheader-wrapper">
        <div class="htmlheader-left">
            {{ logo_svg|string|safe }}
        </div>
        <div class="htmlheader-right">
            <hgroup id="reportheader">
                <h2 class="report-title" {{ report.name }}</h2>
                {% if report.subtitle %}
                <p>{{ report.subtitle }}</p>
                {% endif %}
            </hgroup>
        </div>
    </div>
  </body>
</html>

footer_template.html

<!DOCTYPE html>
<html lang="fr-CA">
  <head>
    <meta charset="utf-8">
    <style>
        {{ css|safe }}
    </style>
  </head>
  <body>
    <div class="htmlfooter-wrapper">
        <div class="htmlfooter-left">
            {% if report.footerleft %}
            <span>
                {{ report.footerleft }}
            </span>
            {% endif %}
        </div>
        <div class="htmlfooter-center">
            {% if report.footercenter %}
            <span>
                {{ report.footercenter }}
            </span>
            {% endif %}
        </div>
        <div class="htmlfooter-right">
            <span class="pageNumber"></span>
        </div>
    </div>
  </body>
</html>

and the CSS -- defines footer left, center or right elements:

@page {   
    margin: 1.5in 0.5in 1.0in 0.5in;
    padding: 0;   
    size: letter landscape;
}

.htmlfooter-wrapper {
  display: grid;
  width: calc(100% - 1in);
  margin-left: 0.5in;
  margin-bottom: 0.25in;
  grid-template-columns: repeat(3, 1fr);
  gap: 0.25in;
  }

  .htmlfooter-left {
  grid-row-start: 1;
  grid-row-end: 2;
  grid-column-start: 1;
  grid-column-end: 2;
  text-align: left;
  }

  .htmlfooter-center {
  grid-row-start: 1;
  grid-row-end: 2;
  grid-column-start: 2;
  grid-column-end: 3;
  text-align: center;
  }

  .htmlfooter-right {
  grid-row-start: 1;
  grid-row-end: 2;
  grid-column-start: 3;
  grid-column-end: 4;
  text-align: right;
  }

  .htmlheader-wrapper {
    display: grid;
    width: calc(100% - 1in);
    margin-left: 0.5in;
    margin-top: 0.25in;
    grid-template-columns: 1fr 4fr;
    gap: 0.125in;
    }
  
    .htmlheader-left {
    grid-row-start: 1;
    grid-row-end: 2;
    grid-column-start: 1;
    grid-column-end: 2;
    text-align: left;
    vertical-align: top;
    overflow: visible;
    }
  
    .htmlheader-right {
    grid-row-start: 1;
    grid-row-end: 2;
    grid-column-start: 2;
    grid-column-end: 6;
    text-align: right;
    }

PDF creation:

with sync_playwright() as playwright:
    browser = playwright.chromium.launch(headless=True)
    context = browser.new_context()
    page = context.new_page()
    page.goto("file:///path/to/file", wait_until="networkidle")
    pdf_bytes = page.pdf(
        display_header_footer=True,
        landscape=True,
        print_background=True,
        prefer_css_page_size=True,
        header_template=header_template.render(
            report=report,
            logo_svg=svg_as_string,
        ),
        footer_template=footer_template.render(report=report, css=css_as_string),
    )

@DaveNatalieTripArc
Copy link
Author

@leducvin This is great info, thanks for posting.

I am just left with one question that is preventing me from using Playwright in my project.

Is it possible, using Playwright, to avoid showing the header and footer on the first page?

@leducvin
Copy link

leducvin commented Sep 27, 2022

@DaveNatalieTripArc Unfortunately, I don't know the answer to that question, but I suspect it's not possible in the current state. It seems like it's either with or without for all pages.

@pavelfeldman
Copy link
Member

Why was this issue closed?

Thank you for your contribution to our project. This issue has been closed due to its limited upvotes and recent activity, and insufficient feedback for us to effectively act upon. Our priority is to focus on bugs that reflect higher user engagement and have actionable feedback, to ensure our bug database stays manageable.

Should you feel this closure was in error, please create a new issue and reference this one. We're open to revisiting it given increased support or additional clarity. Your understanding and cooperation are greatly appreciated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants