Re-displaying the current heading after a page break

烂漫一生 提交于 2021-02-18 06:59:09

问题


I'm creating a document with WeasyPrint. I have sections that have names, some of which might span across multiple pages. When a section is too long, a page break occurs. What I am trying to do is to re-display the current section's name, ideally with the same formatting.

The following MWE shows how the section title is not displayed after a page break:

<html>
    <body>
        <h1>First section</h1>
        <p>Lorem ipsum...</p>
        <p>Lorem ipsum...</p>
        <p>Lorem ipsum...</p>
        <p>Lorem ipsum...</p>

        <p style="break-after: always;"></p>

        <p>Lorem ipsum...</p>
    </body>
</html>

Output of weasyprint example.html example.pdf:

I want First section to be displayed, as a <h1> tag, at the top on the left page.

I would like to do as this tex.stackexchange post which, as I understand it, basically consists in checking if the current page number exceeds the current total page count, and if it does, inserting the last section title encountered.

I'm not aware of the possibility to do so in HTML, does it exist? Is there any workaround to do this? If not, is it possible to have WeasyPrint execute custom Python code on some page-break hook?


回答1:


While it is not possible at this time, you can still use an awesome workaround.

When printing, only three kind of elements are automatically reproduced on each page:

  • elements with fixed position
  • headers, declared with @top-left, @top-center, @top-right etc.
  • footers, declared with @bottom-left etc.

We have to use one of them to build up a css-only solution: we will choose headers. So, the first part of the question is: how can I set a different header for each page? Or, in other words, how can I set a chapter's header?

Achieving this goal is quite simple: once decided which tag or class should contain the chapter's title, set a new CSS string for it:

h1 {
  string-set: doctitle content();
}

Then display the string in the header:

@page {
  size: A4;
  margin: 1.6cm .6cm 1.2cm .6cm;

  @top-center {
    content: string(doctitle);
  }
}

Now you will have something like this:

Let me add some code to your:

<html>
    <body>
        <h1>First section</h1>
        <p>Lorem ipsum...</p>
        <p>Lorem ipsum...</p>
        <p>Lorem ipsum...</p>
        <p>Lorem ipsum...</p>

        <p style="break-after: always;"></p>

        <p>Lorem ipsum...</p>

        <h1>Second section</h1>
        <p>Lorem ipsum 2...</p>
        <p>Lorem ipsum 2...</p>
        <p>Lorem ipsum 2...</p>
        <p>Lorem ipsum 2...</p>

        <p style="break-after: always;"></p>

        <p>Lorem ipsum 2...</p>
    </body>
</html>

In this case your headers will be:

  • 1st page: "First section"
  • 2nd page: "First section"… then will start the second section in the same page, with his own title
  • 3rd page: "Second section"

Next step: set same style for headers and chapter's titles, so headers can have the same appearance as titles:

h1 {
  string-set: doctitle content();
  font-family: 'Liberation Serif';
  font-size: 28pt;
  line-height: 1.2em;
}

@page {
  size: A4;
  margin: 1.6cm .6cm 1.2cm .6cm;

  @top-left {
    content: string(doctitle);
    font-family: 'Liberation Serif';
    font-size: 28pt;
    line-height: 1.2em;
  }
}

Then you will have something like this:

Now, we need to fix the latest issue: the title in the first page looks like duplicated, because of the presence of both title and header.

Fixing it is quite simple:

body h1:first-of-type {
  position: absolute;
  left: -30cm;
}

I have positioned the first title outside the printing area. Unfortunately setting it to display: none will cause that not even the header will be displayed. You have other alternatives, such as visibility: hidden or font-size: 0 or color: transparent, but these three options will always let some blank space between the header and the first paragraph.

Now probably it's time to increase the header's height, adding top-padding to @top-left; The result should look like this:

This technique is not 100% safe: if a chapter that is not the first one will coincidentally start in a new page, both header and title will be shown, one close to the other. In any case this is not a frequent scenario.

Further improvements can consider a different approach to page breaks.

<html>
    <body>
        <section class="chapter">
            <h1>First section</h1>
            <p>Lorem ipsum...</p>
            <p>Lorem ipsum...</p>
            <p>Lorem ipsum...</p>
            <p>Lorem ipsum...</p>
            <p>Lorem ipsum...</p>

            <h1>Second section</h1>
            <p>Lorem ipsum 2...</p>
            <p>Lorem ipsum 2...</p>
            <p>Lorem ipsum 2...</p>
        </section>
        <section class="chapter">
            <h1>Third section</h1>
            <p>Lorem ipsum 3...</p>
            <p>Lorem ipsum 3...</p>
            <p>Lorem ipsum 3...</p>
            <p>Lorem ipsum 3...</p>
        </section>
    </body>
</html>

Styling page-breaks on chapters, and managing title hiding for the first child of any chapter:

section.chapter {
    break-after: always;
}
section.chapter h1:first-of-type {
    position: absolute;
    left: -30cm;
}


来源:https://stackoverflow.com/questions/53322647/re-displaying-the-current-heading-after-a-page-break

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!