How to make figure caption text have the same width as the figure?

Hello!

Suppose I have a figure:

How to do this in typst?

A MWE using rect here:

#figure(
  rect(width:10cm, height: 5cm),
  caption: 
    [_A coastal hydrodynamics simulation of wave impact on a light house using a particle based approach. Figure courtesy of Ihmsen et al._]
) 

Can I make it a default somehow?

Kind regards

Hi, you can use a show rule on the figure to measure its size, and use a nested show rule on the caption to restraining its size to the previously measured one.

I believe this to be what you’re going for:

#set page(width: auto, height: auto, margin: 2em)
#show figure: it => {
	let w = measure(it.body).width
	set par(justify: true)
	show figure.caption: cap => box(width: w, cap)
	it
}

#figure(
  rect(width:10cm, height: 5cm),
  caption:
    [_A coastal hydrodynamics simulation of wave impact on a light house using a particle based approach. Figure courtesy of Ihmsen et al._]
)

which creates
image

1 Like

Amazing!

Just one question, if you use an actual image and set width to: width: 60% does the function you made also break for you? I get a width of 0pt in that case…

Kind regards

in that case you need to still wrap in in a layout call, to give it the context it needs

#show figure: it => layout( sz => {
	let w = measure(
			it.body,
			width: sz.width
		).width
	set par(justify: true)
	show figure.caption: cap => box(width: w, align(left,emph(cap)))
	it
})

3 Likes

Amazing, thanks a ton!

What is it that the layout does and how do I know when to use it? I don’t think I would have realized that on my own…

1 Like

I find typst has great documentation, it’s worth going through to find out what’s even possible.

The layout function makes the dimensions of the parent container available. Setting your width: 60% is 60% of the parent’s dimensions + 0pt of absolute size. Without the knowledge of the parent’s dimensions only the 0pt remains, which is why the first solution broke for relative sizes.

2 Likes

The trick to wrap the caption in a box which worked in typst 0.12 seems to be broken in typst 0.13, see Paragraph justification sometimes doesn't use the full page width · Issue #5472 · typst/typst · GitHub

I had to replace

show figure.caption: cap => box(width: w, cap)

with

show figure.caption: it => box(width: w, context[
  #it.supplement #it.counter.display()#it.separator#it.body
])

to get it to work again

Can you give a small example that shows the problem with Typst 0.13? The examples from @slowjo seem to work fine in 0.13.1

@sijo My previous reply contains a link to a github issue that shows a minimized example.

You will only see it if - without justification - the caption is smaller than the figure width. Then - with justification - it is not streched horizontally to the width of the figure, but only to the width of the longest line.
For the example given above, the difference between the width of the longest line and the figure might be a few pixels only, and thus it might not be apparent. The example I linked makes it clear.