Skip to content

【已修复】列表符号/编号和内容错位怎么办?

【已修复】列表符号/编号和内容错位怎么办?

✅ Typst 0.15 已修复

#7895 已让listenum第一行对齐基线,现在应该基本没有错位问题了。

typst
#set text(font: ((name: "New Computer Modern", covers: "latin-in-cjk"), "SimSun"))

= `enum`
+ 鲁镇的酒店的格局
+ abc $display(integral)_a^b$
+ def #box(stroke: 1pt, inset: 3mm, baseline: 3mm)[test]

= `list`
- 鲁镇的酒店的格局
- abc $display(integral)_a^b$
- def #box(stroke: 1pt, inset: 3mm, baseline: 3mm)[test]
Typst compiled imageTypst compiled image

现象

分别设置中西文字体,导致符号/编号与内容错位

若分别设置了中西字体,那么即使只写汉字,enumlist 的符号/编号和内容也可能错位,例如下图:

typst
#set text(font: ((name: "New Computer Modern", covers: "latin-in-cjk"), "SimSun"))

= `enum`
+ 鲁镇的酒店的格局

= `list`
- 鲁镇的酒店的格局
Typst compiled image

并非最新版

上例使用 v0.14.2 编译,可能不适用于最新版。

并且直接写编号完全正常:

typst
#[1.] 鲁镇的酒店的格局
Typst compiled image

并非最新版

上例使用 v0.14.2 编译,可能不适用于最新版。

已知存在问题的字体组合

  • 西文:New Computer Modern / Libertinus Serif
  • 中文:中易宋体/方正书宋/方正新书宋

复杂内容块或行内公式,导致符号/编号与内容错位

如果行内有额外高度的 box 或者行内公式,会撑高内容块的高度,导致符号/编号与内容错位,例如下图:

typst
= `enum`
+ abc $display(integral)_a^b$
+ def #box(stroke: 1pt, inset: 3mm, baseline: 3mm)[test]

= `list`
- abc $display(integral)_a^b$
- def #box(stroke: 1pt, inset: 3mm, baseline: 3mm)[test]
Typst compiled image

并非最新版

上例使用 v0.14.2 编译,可能不适用于最新版。

解决方法

推荐方法:使用 itemize

itemize 包可以解决大多数符号/编号与内容错位的问题

typst
#import "@preview/itemize:0.2.0" as el  
#show: el.default-enum-list 

#set text(font: ((name: "New Computer Modern", covers: "latin-in-cjk"), "SimSun"))

= `enum`
+ 鲁镇的酒店的格局

= `list`
- 鲁镇的酒店的格局
Typst compiled image

并非最新版

上例使用 v0.14.2 编译,可能不适用于最新版。

typst
#import "@preview/itemize:0.2.0" as el  
#show: el.default-enum-list 

= `enum`
+ abc $display(integral)_a^b$
+ def #box(stroke: 1pt, inset: 3mm, baseline: 3mm)[test]

= `list`
- abc $display(integral)_a^b$
- def #box(stroke: 1pt, inset: 3mm, baseline: 3mm)[test]
Typst compiled image

并非最新版

上例使用 v0.14.2 编译,可能不适用于最新版。

具体可参考其 Typst Universe 页面

其它方法

以下是早期文档中提及的其它方法,这里保留并折叠,可供额外参考:

点击展开

如果只写汉字

法一:数字也用中文字体

typst
#set text(font: "SimSun")
+ 鲁镇的酒店的格局
Typst compiled image

法二:修改编号对齐方式

typst
#set text(font: ((name: "New Computer Modern", covers: "latin-in-cjk"), "SimSun"))

= `enum`
#set enum(number-align: bottom) 
+ 鲁镇的酒店的格局

= `list`
#set list(marker: ([•], [‣], [–]).map(align.with(horizon)))  
- 鲁镇的酒店的格局
Typst compiled image

法三:修改汉字边框计算方式

typst
#set text(font: ((name: "New Computer Modern", covers: "latin-in-cjk"), "SimSun"))

#set text(top-edge: "ascender", bottom-edge: "descender") 

= `enum`
+ 鲁镇的酒店的格局

= `list`
- 鲁镇的酒店的格局
Typst compiled image

不过这样会在视觉上增大行距,详见文字外框的解释

如果列表内容复杂

来自 @OrangeX4 的解决方案

typst
/// Align the list marker with the baseline of the first line of the list item.
///
/// Usage: `#show: align-list-marker-with-baseline`
#let align-list-marker-with-baseline(body) = {
  show list.item: it => context {
    let current-marker = {
      set text(fill: text.fill)
      if type(list.marker) == array {
        list.marker.at(0)
      } else {
        list.marker
      }
    }
    let hanging-indent = measure(current-marker).width + .6em + .3pt
    set terms(hanging-indent: hanging-indent)
    if type(list.marker) == array {
      terms.item(
        current-marker,
        {
          // set the value of list.marker in a loop
          set list(marker: list.marker.slice(1) + (list.marker.at(0),))
          it.body
        },
      )
    } else {
      terms.item(current-marker, it.body)
    }
  }
  body
}

/// Align the enum marker with the baseline of the first line of the enum item. It will only work when the enum item has a number like `1.`.
///
/// Usage: `#show: align-enum-marker-with-baseline`
#let align-enum-marker-with-baseline(body) = {
  show enum.item: it => context {
    if not it.has("number") or it.number == none or enum.full == true {
      // If the enum item does not have a number, or the number is none, or the enum is full
      return it
    }
    let weight-map = (
      thin: 100,
      extralight: 200,
      light: 300,
      regular: 400,
      medium: 500,
      semibold: 600,
      bold: 700,
      extrabold: 800,
      black: 900,
    )
    let current-marker = {
      set text(
        fill: text.fill,
        weight: if type(text.weight) == int {
          text.weight - 300
        } else {
          weight-map.at(text.weight) - 300
        },
      )
      numbering(enum.numbering, it.number) + h(-.1em)
    }
    let hanging-indent = measure(current-marker).width + .6em + .3pt
    set terms(hanging-indent: hanging-indent)
    terms.item(current-marker, it.body)
  }
  body
}

#show: align-list-marker-with-baseline
#show: align-enum-marker-with-baseline

- 1 + $display(integral) + x$
- 1 + $display(integral)$

1. 1 + $display(integral) + x$
2. 1 + $display(integral)$
Typst compiled image

参考阅读

修复列表的终极方案 页面中提及了另一种实现符号/编号与内容正确对齐的方法,其实现效果在默认情况下会使内容延伸到编号下方的空白处,可另行参考。

另请参见

贡献者

The avatar of contributor named as Y.D.X. Y.D.X.The avatar of contributor named as Copilot CopilotThe avatar of contributor named as jkjkil4 jkjkil4
The avatar of contributor named as QuadnucYard QuadnucYard
The avatar of contributor named as Hong Jiarong Hong Jiarong
The avatar of contributor named as OrangeX4 OrangeX4
The avatar of contributor named as flaribbit flaribbit
The avatar of contributor named as 梦飞翔 梦飞翔

页面历史

Comments
  • Latest
  • Oldest
  • Hottest

基于 MIT 许可发布