How can I suppress headers and footers on blank verso/trailing pages

My document uses facing pages and Hydra to create the headings; page numbering is default in the footer. It is set to have each level 1 heading (in this minimal example “Part”) open on a recto/leading page. This means that if the preceding text ends on a recto page, there is a blank verso/trailing page between it and the new Part. Here is the example code:

#import "@preview/hydra:0.6.1": hydra

#set page(paper: "a7", margin: (inside: 1.5cm, outside: 1cm, y: 2cm), numbering: "1", header: context {
  if calc.odd(here().page()) {
    align(right, smallcaps(hydra(1)))
  } else {
    align(left, emph(hydra(2)))
  }
})

#show heading.where(level: 1): set align(center)
#show heading.where(level: 1): set text(18pt, weight: "semibold")
#show heading.where(level: 1): it => pagebreak(weak: true, to: "odd") + it

#show heading.where(level: 2): set text(14pt, weight: "semibold")

= Part 1

#lorem(75)

== Section 1.a

#lorem(25)

= Part 2

#lorem(75)

== Section 2.a

#lorem(25)

As the example shows, blank verso pages (page 4) have the header and footer. I want to have no header or footer on any such blank pages. I found a discussion on

which included this code:

// make pagebreaks detectable
#show pagebreak: it => {
  [#metadata(none) <empty-page-start>]
  it
  [#metadata(none) <empty-page-end>]
}

// check whether this is an empty page
#let is-page-empty() = {
  let page-num = here().page()
  query(selector.or(<empty-page-start>, <empty-page-end>)).chunks(2).any(((start, end)) => {
    start.location().page() < page-num and page-num < end.location().page()
  })
}

// skip footer on empty pages
#set page(
  numbering: "1 / 1",
  footer: context if not is-page-empty() {
    counter(page).display(page.numbering, both: true)
  },
)

That removes the footer on the blank pages as I wish, however (1) it changes the page numbering to the left margin on all other pages when I want it centred, and (2) it does not remove the header. Could someone please show me how to achieve (1) and (2)?

:slight_smile:
Mark

  1. Use align(center).
  2. Add the condition to the header.
#import "@preview/hydra:0.6.1": hydra

/// Check whether this is an empty page.
#let is-page-empty() = {
  let page-num = here().page()
  query(selector.or(<ep-start>, <ep-end>))
    .chunks(2)
    .any(((start, end)) => {
      start.location().page() < page-num and page-num < end.location().page()
    })
}

#set page(
  paper: "a7",
  margin: (inside: 1.5cm, outside: 1cm, y: 2cm),
  header: context if not is-page-empty() {
    if calc.odd(here().page()) {
      align(right, smallcaps(hydra(1)))
    } else {
      align(left, emph(hydra(2)))
    }
  },
  footer: context if not is-page-empty() {
    align(center, counter(page).display())
  },
)

#show pagebreak: it => [#metadata[]<ep-start>] + it + [#metadata[]<ep-end>]

#show heading.where(level: 1): set align(center)
#show heading.where(level: 1): set text(18pt, weight: "semibold")
#show heading.where(level: 1): it => pagebreak(weak: true, to: "odd") + it

#show heading.where(level: 2): set text(14pt, weight: "semibold")

= Part 1
#lorem(75)

== Section 1.a
#lorem(25)

= Part 2
#lorem(75)

== Section 2.a
#lorem(25)

1 Like

Thank you Andrew! That solves that one. I have to say that I don’t really understand how the code works, nor the importance or otherwise of the (seemingly small) differences between your version and the one from the GitHub discussion. But the effect is that although adding align(center) is the obvious solution, where to fit it into the code is not so obvious to one who can’t read the code easily; the same for adding the context… to the header code.

But I thank you for your help.

:slight_smile:
Mark

Your page numbering is in the footer, and by design in Typst, this is configured by defining options for page, in particular the option “footer”.
If you are writing in a LTR language, then everything is mostly left-aligned by default. Hence, when you are setting the page footer, the content is counter(page).display(), but left-aligned. Then, you can simply define the content alignment with an align element.

As for the context expression, understand it conceptually as wrapping location-dependent code. Location is not provided to normal code, so you need it wrapped in context.

As for the trick used here, very briefly, because a pagebreak is also an element, then you can re-define it to also raise a “start” and an “end” flag (metadata), and return “yes, the page is empty”, if you are currently between any of these two flags.

Thank you very much for the explanations. They do help, but if I can elaborate a bit further—though this is related to my post in

In this code heading 1 is defined by:

#show heading.where(level: 1): set align(center)
#show heading.where(level: 1): set text(24pt, weight: "regular")
#show heading.where(level: 1): smallcaps
#show heading.where(level: 1): it => pagebreak(weak: true, to: "odd") + it

In itself, this works just as I want. However, I would like, book-style, to have a blank space of say 5em above the heading.

The Hydra Guide says:

You should also make sure you don’t use show rules which affect the vertical starting position of the heading.

// do

#show heading: it => block(v(8cm) + it)
…

However, it is far from clear, how that can be combined with my heading 1 code. Everything I have tried either results in an error I can’t resolve or all text being relaced with the string block(5em). If I create a separate show rule for it

#show heading.where(level: 1): set block(above: 5em)

it is ignored wherever I place it in relation to the other heading 1 show rules.

I think I understand all the code involved, but it is how to combine them that is always the problem for beginners like me.

:slight_smile:
Mark

You’re welcome Mark! I have to agree with you, the documentation is very beginner-friendly at all. I would say, please don’t feel ashamed of asking questions here, I think it should be the opposite actually. Basic questions on the forum reflect badly on the state of the documentation itself, or on the discoverability of basic information.

About the show rules combination, I think it’s best to create one rule per document you are writing. Styling composability is ambiguous to the user, especially when loading packages, etc. This is a pain point of Typst.

I believe you would find the answers at Which show rule takes precedence? interesting. As for the question itself, could I trouble you to create a new topic in Questions?