I control the spacing round my headings like this:
#show heading.where(level:1): it => {
v(1cm)
it
v(1cm)
}
#show heading.where(level:2): it => {
v(0.5cm)
it
v(0.5cm)
}
However, when I have a heading immediately followed by a subheading, I run into the problem that the spacing of the two headings compound, creating a way too large gap:
= heading
== subheading
How can I apply the spacing differently depending on if the content before a heading is also a heading? My first thought was to query the content immediately before the heading and detect whether it is also a heading or another form of content. However, I did not find a way to access the general content immediately before a heading with selectors without using a specific element function. I also found this issue, but it does not seem solved: Ability to specify spacing between (heading and heading) & (heading and text) · Issue #4281 · typst/typst · GitHub
#show heading: it => {
// Clever trick to reduce spacing between consecutive headings
// See https://github.com/typst/typst/issues/2953
let previous_headings = query(selector(heading).before(here(), inclusive: false))
if previous_headings.len() > 0 {
let ploc = previous_headings.last().location().position()
let iloc = it.location().position()
if (iloc.page == ploc.page and iloc.x == ploc.x and iloc.y - ploc.y < 30pt) {
// threshold
v(-10pt) // amount to reduce spacing, could make this dependent on it.level
}
}
it
}
For your use case of avoiding excessive spacing you could also try v.weak.
For example:
#show heading.where(level:1): it => {
v(1cm, weak: true)
it
v(1cm, weak: true)
}
#show heading.where(level:2): it => {
v(0.5cm, weak: true)
it
v(0.5cm, weak: true)
}
Though might be good to be a bit careful with using weak: true, and check if this actually works well for your use case, because it also affects for example spacing in front of or behind adjacent paragraphs.
Thanks, that also seems to work! Currently, the solution with the weak spacing seems to solve my problem though, so I’m going to stick to that as long as it works since it is simpler and less dependant on an arbitrary threshold.
The built-in styles for headings uses the style fields block.above and block.below to control this spacing. This spacing also has weak semantics, adjacent weak spacing is collapsed/combined.
If you can, I think it’s intended to use that way for this customization, but it should look identical in the end result
#show heading.where(level: 1): set block(above: 1cm, below: 1cm)
#show heading.where(level: 2): set block(above: 0.5cm, below: 0.5cm)