I want to place some content fixed on a page (in my case center+horizon) and then just continue with the rest of the content below it.
If I use
#set align(center + horizon)
Content 1
Content 2
The combination of Content 1 and 2 will be placed in the middle of the page. But I want Content 1 to be centered vertically (horizon) and then continue with the rest below it.
I see, I didn’t realise that it interacted in this way. I don’t think this is “natively” supported by typst but you could pad the content manually:
#let force-center(content) = layout(container => [
#let content-height = measure(content, width: container.width).height
#let top-margin = if page.margin == auto {
2.5 / 21 * calc.min(page.width, page.height)
} else if type(page.margin) == relative {
page.margin
} else if page.margin.top == auto {
2.5 / 21 * calc.min(page.width, page.height)
} else {
page.margin.top
}
// margin calculation inspired by:
// https://forum.typst.app/t/how-to-draw-at-the-margin-of-a-page/1708/2
#let offset = here().position().y - top-margin
// the offset ensures that content is in the center even if the page is not empty
#pad(
top: (container.height - content-height) / 2 - offset,
content
)
])
#force-center(box(fill:green, width:80%, height: 3cm)[Content 1])
I am below the box!
To recap what this is about, you’re is asking for a fixed blue rectangle that affects layout. So here’s possible code for that, using v instead of align(horizon):
I only considered your specific use and assumed this would only be used on whole pages. A better approach to remedy both of these could probably be pad.
Even then, your margin is most likely not 0mm. I believe whatever margin you have would need to be added in all these approaches. By this stage, clearly a simpler solution exists? I seem to have been too late to reply!
This is very elegant, but note that if Content 2 is long it won’t break onto the next page, even if grid.cell.breakable is set to true (which seems like a bug?).
You are right that my solution errors out if the page margins are a dictionary, i’ve edited my answer accordingly. Whereas for behaviour, if Content 1 should be placed in the center of the margined area, my previous answer behaves as expected. If it should be placed in the center regardless of margins, we can get rid of the margin calculations altogether:
#let force-center(content) = layout(container => [
#let content-height = measure(content, width: container.width).height
#let offset = here().position().y
// the offset ensures that content is in the center even if the page is not empty
#pad(
top: (page.height - content-height) / 2 - offset,
content
)
])