Get current page margins in typst

223 Views Asked by At

In typst I want to write code that does something if the current location is at (or close to) the left-hand margin.

How can I get the value of the current page margins as numbers?

For example, the code below does what I want with the default 25mm margins, but I want it to work with arbitrary page margins. So I want to change the hard-coded 25 to a function which returns the current left margin value, in mm, as a number.

#let lr() = locate(l=>if l.position().x.mm()<=25 [*left* ] else  [_right_ ])

#let n = 0
#while n < 100 {
  n = n+1
  [#lr()]
}

output

2

There are 2 best solutions below

0
ntjess On

Why not just put a label at the start of your page as a reference for the left margin?

<start-of-line>
#let lr() = locate(loc => {
  let start-of-line = query(<start-of-line>, loc).last().location().position().x
  if loc.position().x == start-of-line {
    box[*left*]  
  } else {
    box[_right_]
  }
})
#for _ in range(100) [
 #lr()
]

enter image description here

However, if you're here from Google and want to get the page margins for a different reason, keep reading.

Getting page margins

This is not currently possible without unstable hacks. You can track the status of https://github.com/typst/typst/issues/763 for when this is supported by the language.

In the meantime, you can use the following if you really need margin values:

#let bg-state = state("background-size", (width: 0pt, height: 0pt))
#let margins = state("margin-state", (:))

#let background-sizer = {
  layout(size => {
    bg-state.update(size)
  })
}
#set page(background: background-sizer, margin: (left: 100pt, right: 150pt))

// This has to be outside all containers (i.e. at the page level) work properly
#locate(loc => {
  let page-size = bg-state.at(loc)
  layout(size => {
    let left-margin = loc.position().x
    let right-margin = page-size.width - left-margin - size.width
    margins.update(old => (left: left-margin, right: right-margin))
  })
})

#lorem(25)

#margins.display()

The margin state will hold your page margins as a dictionary. enter image description here

0
Martin On

With Typst 0.11 and context you can access the values set by set rules. Hence, you could use this snippet:

#set page(margin: (left: 10%))
#context {
  // In Typst 0.11, `auto` is not yet resolved in context blocks so we
  // need to check for it and apply the default
  let left = if page.margin == auto or page.margin.left == auto {
    25mm
  } else {
    // l.position returns a length but page.margin.left returns a relative
    // length. We resolve it here manually.
    page.margin.left.length + page.margin.left.ratio * page.width
  }

  let lr() = locate(l=> if l.position().x <= left [*left* ] else  [_right_ ])

  let n = 0
  while n < 100 {
    n = n+1
    [#lr()]
  }
}

As you see above, there are still some peculiarities with regards to the resolution of auto and relative lengths, but we expect to fix that in the future.