How to adjust numerator fraction line vertical spacing?

I want to adjust the black equation in the image to make the spacing between the numerator and the fraction line equal to the purple equation’s spacing. How should I write the code? I think the purple equation has more aesthetically pleasing formatting.


This solution is admittedly a bit hacky. However, since there is no (documented) way to adjust the spacing between the numerator and denominator, recreating the frac function was the only viable approach I found.

#show math.frac: it => {
  context {
    let width = calc.max(measure($it.num$).width, measure($it.denom$).width)
    stack(spacing: 0.25em, 
      $it.num$,
      line(stroke:0.5pt, length: width),
      $it.denom$)
  }
}

$ a^2/b + x/y = 1 $

image

https://typst.app/project/reQMeWLVRNivMbaUZgRYSd

Hello. There is no way to adjust that with rules, so you can open an issue about it.

By looking at typst/crates/typst-layout/src/math/frac.rs at 7e072e24930d8a7524f700b62cabd97ceb4f45e6 · typst/typst · GitHub, the default show rule is pretty big and it uses a lot of things that do not exist in Typst, but here is roughly how it works for frac:

#show math.equation.where(block: true): it => {
  show math.frac: it => context {
    let num-vert-spacing = 2pt
    let thickness = 0.045em.to-absolute()
    let around = 0.1em

    // Grabbed from font, it looks like.
    let axis = -0.55em.to-absolute() // denom/line
    let shift-up = 0pt // denom + line
    let shift-down = 0.45em.to-absolute() // denom + other stuff
    let num-descent = 0pt // denom + line
    let denom-ascent = -0.35em.to-absolute() // denom + other stuff
    let num-min = 0.1em.to-absolute() // denom + line
    let denom-min = 0.1em.to-absolute() // denom + line

    let num-size = measure(it.num)
    let denom-size = measure(it.denom)

    import calc: max
    let num-gap = max(shift-up - (axis + thickness / 2) - num-descent, num-min)
    let denom-gap = max(shift-down + (axis - thickness / 2) - denom-ascent, denom-min)
    let line-width = max(num-size.width, denom-size.width)
    let width = line-width + 2 * around
    let height = num-size.height + num-gap + thickness + denom-gap + denom-size.height

    let size = (width, height)
    let num-pos = ((width - num-size.width) / 2, 1pt + num-vert-spacing)
    let line-pos = ((width - line-width) / 2, num-size.height + num-gap + thickness / 2)
    let denom-pos = ((width - denom-size.width) / 2, height - denom-size.height)
    let baseline = line-pos.last() + axis

    let frame = box.with(width: size.first(), height: size.last())
    frame = frame.with(baseline: baseline)
    frame({
      place(dx: num-pos.first(), dy: num-pos.last(), $it.num$)
      place(dx: denom-pos.first(), dy: denom-pos.last(), $it.denom$)
      place(
        dx: line-pos.first(),
        dy: line-pos.last(),
        line(length: line-width, stroke: thickness)
      )
    })
  }
  it
}

image

It has different values for display/non-display variants, so I only played with block equation, for inline on the values should be different.

The only problem with it is that the values are manually assigned, and the end result is slightly different: the line width is slightly different, the x position is slightly changed. The only noticeable change I had to make is add 1pt to the numerator y value, because the zero looks way off from the default look.