FrameSeq

样式#

全局的配色、字体、间距和圆角先看 Themes(英文)。下面这些修饰符是针对单个对象覆盖主题的。

内容命令和底层组件都返回构建器,每个修饰符也返回同一个构建器,所以可以一直链下去:

text("Important")
  .size(pt(30))
  .bold()
  .color("#38bdf8")
  .margin(12, 0);

全局排版#

想保留主题的配色和布局、但换一套字体默认值时,用 presentation()font 选项:

presentation({
  title: "My Slides",
  theme: "minimal-academic",
  font: {
    family: '"Noto Sans SC", sans-serif',
    size: 24,
    weight: 400,
    lineHeight: 1.5,
    heading: {
      family: '"Noto Serif SC", serif',
      size: 40,
      weight: 700,
    },
    code: {
      family: '"JetBrains Mono", monospace',
      size: 18,
    },
  },
});

size 处的数字是像素。也接受长度助手和 CSS 字符串,比如 pt(20)"1.5rem""24px"lineHeight 可以是无单位数字或 CSS 字符串。

优先级是:单个对象的修饰符或 .style() 值 > presentation.font > 所选主题。顶层的 family 同时作用于正文和标题;代码保持主题的等宽字族,除非设置了 code.family

中文、日文、韩文默认可用:每套内置主题的字族链末尾都带 CJK 回退,详见 Themes(英文)。

长度与单位#

数字按像素解释:

text("Pixels").size(24);

需要显式单位时用助手函数:

px(20)
pt(20)
rem(2)
percent(50)
vw(40)
vh(30)

它们返回 CSS 长度字符串,任何接受 Length 的地方都能用。

尺寸与间距#

.width(640)
.height(percent(100))
.minWidth(200)
.minHeight(120)
.maxWidth(720)
.maxHeight(400)
.padding(24)
.padding(16, 24)               // 纵向, 横向
.padding({ top: 8, left: 16 }) // 单独设置某几边
.margin(12)
.margin(8, 16)                 // 纵向, 横向
.margin({ bottom: 24 })        // 单独设置某几边
.gap(20)
.gap(12, 40)                   // 先行间距,后列间距

maxWidth() 是把一段正文限制在易读行宽内的办法。padding()margin() 的对象形式里,没写的边是 0——和 CSS 简写一样:padding({ top: 8 }) 会把其余三边设为 0,而不是保持不变。

外观#

.background("#0f172a")
.color("#f8fafc")
.border("1px solid #334155")
.radius(16)
.opacity(0.8)

字体#

.size(pt(28))
.fontSize(pt(28))
.weight(600)
.fontWeight(600)
.bold()
.lineHeight(1.4)
.textAlign("center")

size()fontSize() 的别名,weight()fontWeight() 的别名。

文字角色提供带语义的默认值:

.body()
.title()
.hero()
.subtitle()
.author()
.eyebrow()
.lead()
.caption()
.quote()

这些角色可用于小写的 text() 命令返回的对象。

弹性布局#

下面这些修饰符每个对象都能调用,但它们是被布局的不同部分回答的。这三类作用于对象自己的子对象,所以需要它本身是行、列或网格:

.row()
.column()
.stack()
.grid(3)
.center()
.align("center")
.justify("space-between")
.wrap()
.alignContent("center")

另外这几个描述的是这个对象在容器里怎么摆,所以需要那个容器是行、列或网格:

.selfAlign("center")
.centerSelf()
.grow()

align()selfAlign()alignContent() 接受 "start""center""end""stretch";justify() 接受 "start""center""end""space-between""space-around""space-evenly",alignContent() 也接受这些分布方式,并且只有开了 wrap() 才有意义。

align()selfAlign() 作用在横跨区域的方向——列里是水平,行里是垂直——而 justify() 作用在沿着区域的方向。完整对照表见各个修饰符动的是哪根轴;只居中一个对象而不是整个区域,见只让一个对象居中

对象默认在交叉轴上拉伸,所以只有当它自己有尺寸时 selfAlign() 才会让它移动——在列里是 width(),在行里是 height()

修饰符落到不可能生效的地方时,浏览器会一声不响地忽略它。frameseq check 会把这类问题报成 inert-modifier,而不是让渲染结果和源码悄悄对不上。

定位与变换#

.position({ x: 80, y: 120 })
.anchor("center")
.rotate(-4)

position() 使用绝对定位,面向画布或其它刻意定位过的父容器。anchor() 则相对于父容器摆放,不用写坐标 —— 见 Diagrams(英文)。

要在普通流式布局里放一个定位区域,给容器起个名字并把它变成局部画布:

at("panel").canvas().width(600).height(260).clip();

text("Local coordinates").position({ x: 32, y: 24 });

写在 at("panel") 之后的对象都属于这个容器。它的 .canvas() 让子对象的坐标变成局部的,.clip() 把它们裁在面板内;.clip(false) 可恢复溢出可见。

渐进揭示#

text("Appears first").showAt(1);
text("Appears second").showAt(2);

揭示序号从 1 开始。PDF 和打印模式下所有步骤都可见。

Tailwind CSS#

Tailwind 工具类是内置的,不需要任何配置。把工具类字符串传给 style():

text("A strong statement")
  .style("text-4xl font-bold tracking-tight text-blue-600");

text("Precisely placed")
  .style("absolute left-[80px] top-[120px] w-[640px]");

支持 text-[30px]bg-[#0f172a]grid-cols-[2fr_3fr] 这类任意值。动态选择的工具类要保持为完整字符串,Tailwind 才能扫描到:

const emphasis = important ? "text-red-600" : "text-slate-500";
text("Status").style(emphasis);

不要用 `text-${color}-600` 这种拼接写法 —— 完整的类名没有出现在源码里,Tailwind 找不到它。

内联 CSS 与类名#

对象形式仍然可以写内联 CSS:

text("Custom")
  .className("my-callout")
  .style({
    letterSpacing: "0.08em",
    textTransform: "uppercase",
  });

传给 style() 的属性名用 JavaScript 风格,比如 letterSpacing

内联属性的优先级高于 Tailwind 工具类,与调用顺序无关。 只想附加类名、不想用 style() 简写时,用 className()