I’m trying to create a headline slot with a fixed min-height: I have various titles that should be independently able to outgrow the space. So most paragraphs start at the exact same position on the page and only long outliers move the next paragraph down.
When I’m not measuring my reference block at 100% width the “growing” part does not work and when I add the 100% width I’m starting to measure anything, but not the correct height
Can someone help me get this right please, I can’t get it to work?
Here is my MWE:
#set page(width: 140mm, height: 220mm)
// Toggle debug label rendering
#let debug = true
// Desired minimum height of the heading slot
#let heading-slot = 5em
#show heading.where(level: 1): it => {
show strong: s => {
set text(size: 30pt, fill: red)
set par(leading: 0pt)
block(above: 0pt, below: 0.15em, s.body)
}
context {
let heading-content = align(center, smallcaps(all: true, it.body))
// Variant 1: natural width (comment out to compare)
let measured-height = measure(heading-content).height
// Variant 2: at full text width (comment out to compare)
// let measured-height = measure(block(width: 100%, heading-content)).height
let target-height = measure(block(height: heading-slot)).height
let slot-height = calc.max(measured-height, target-height)
let debug-label = if debug {
align(right, text(6pt, fill: red, [measured: #measured-height, target: #target-height, slot: #slot-height]))
} else {
[]
}
// Fixed-height slot for the heading (debug label + content)
let slot = block(
width: 100%,
height: slot-height,
[#debug-label #heading-content],
)
box(stroke: 0.25pt + blue, slot)
}
}
= Short title with #strong[Short]
First paragraph after short title.
= Medium title with #strong[Two Words]
First paragraph after medium title.
= Long style #strong[Title] in the middle
First paragraph after long title.
= Even longer title with a very long #strong[Strong Part That Wraps To Three Lines]
First paragraph after very long title.
I have a context-less approach: putting each heading in a two-column grid, whose first cell is a zero-width fixed-height block, and the second cell is the real heading. Is that satisfactory?
#set page(width: 140mm, height: 220mm)
// Toggle debug strokes
#let debug = true
// Desired minimum height of the heading slot
#let heading-slot = 5em
#show heading.where(level: 1): it => {
show strong: s => {
set text(size: 30pt, fill: red)
set par(leading: 0pt)
block(above: 0pt, below: 0.15em, s.body)
}
grid(
columns: (0pt, 1fr),
align: center,
stroke: if debug { green + 0.5pt },
block(height: heading-slot), smallcaps(all: true, it.body),
)
}
= Short title with #strong[Short]
First paragraph after short title.
= Medium title with #strong[Two Words]
First paragraph after medium title.
= Long style #strong[Title] in the middle
First paragraph after long title.
= Even longer title with a very long #strong[Strong Part That Wraps To Three Lines]
First paragraph after very long title.
The measure function lets you determine the layouted size of content. By default an infinite space is assumed, so the measured dimensions may not necessarily match the final dimensions of the content. If you want to measure in the current layout dimensions, you can combine measure and layout.
For example:
#context (
// Both are the same as the line height
measure(lorem(5)).height,
measure(lorem(1000)).height,
)
#box(height: 7.24pt, width: 1pt, stroke: green) #lorem(5)
I think the solution using grids is a bit cleaner, but might have some issues with accessibility, as far as I understand things like screenreaders might get confused about there being a grid (although I’m not 100% sure). This is also why it’s recommended to use it instead of it.body whenever possible, as it preserves the structure better :)
Ah, man, thank you both – I should have thought on a meta level too, the grid solution is very elegant. Measure and I are just not friends. But thank you very much @aarnent I will try both, the note about screen readers is actually very valuable too!