How to compute the current page's textwidth

I was missing LaTeX’s \textwidth command, as I needed to use it for some scaling stuff, so here you go:

/// Computes the current page's textwidth
/// -> length
#let textwidth() = context {
  // Margins are set automatically to 2.5/21 times the smaller dimension of the
  // page.
  let default-margin = (2.5 / 21) * calc.min(page.width, page.height)

  if page.margin == auto {
    return page.width - (2 * default-margin)
  }

  if "x" in page.margin {
    return page.width - (2 * page.margin.x.length)
  }

  let left-margin = if "left" in page.margin {
    page.margin.left.length
  } else if "inside" in page.margin {
    page.margin.inside.length
  } else if "rest" in page.margin {
    page.margin.rest.length
  } else { default-margin }

  let right-margin = if "right" in page.margin {
    page.margin.right.length
  } else if "outside" in page.margin {
    page.margin.outside.length
  } else if "rest" in page.margin {
    page.margin.rest.length
  } else { default-margin }

  return page.width - left-margin - right-margin
}

The margins can be configured in many forms (see Page Function – Typst Documentation), so that’s why it’s so long.

TIP: If you’d like to use it inside a context function, just pass page as an parameter:

/// Computes the current page's textwidth
///
/// - page (function): Typst's `page` function
/// -> length
#let textwidth(page) = {
  // ...
}

#let foo() = context {
  textwidth(page)
}
2 Likes

I appreciate your effort, but I belive 100% would address most of the demands, and layout(size => …) can address the others…

2 Likes

Nicely done, this could be contributed as an additional function to scaffolder – Typst Universe

#import "@preview/scaffolder:0.2.1": get-page-margins

/// Computes the current page's textwidth
/// -> length
#let textwidth() = context {
  return page.width - get-page-margins().left - get-page-margins().right
}

#textwidth()
1 Like

Thanks for telling us about this package, I’ve been thinking that a function that resolves the current page margins needed to live in a package - turns out that it already does. :smile:

1 Like

The number of packages is increasing quickly. It is becoming harder to remember them all :sweat_smile:

You’re absolutely right! I didn’t know layout existed…

Bonus tip – a function that scales any content to a width relative to its container:

/// Scales content to the desired width/height relative to its container.
///
/// - body (content): The content to scale
/// - width (ratio, auto): Desired width (relative to its container)
/// - height (ratio, auto): Desired heigth (relative to its container)
/// -> content
#let scale-to-container(body, width: auto, height: auto) = layout(ly => {
  let body-size = measure(body)
  scale(
    x: if width == auto { auto } else { ly.width / body-size.width * width },
    y: if height == auto { auto } else { ly.height / body-size.height * height },
    reflow: true,
    body,
  )
})
1 Like