
前端构建工具开发工具【免费下载链接】panda Universal, Type-Safe, CSS-in-JS Framework for Design Systems ⚡️项目地址https://gitcode.com/gh_mirrors/pa/panda点击查看免费下载导读prose是 Panda CSS 生态中用于文章排版的核心 recipe它针对 Markdown、CMS 富文本、博客正文这类不可控 HTML提供开箱即用的排版样式覆盖标题、段落、列表、引用、代码、表格等元素并通过语义化颜色 token 自动适配深色模式。本文以仓库中的 prose 沙箱sandbox/prose基于 TanStack Router Vite React为主线从运行方式、交互验证到源码原理完整讲解pandacss/preset-typography的尺寸体系、em缩放机制、节奏变量--prose-flow/--prose-leading、not-prose 白名单隔离机制以及语义 token 的自定义方法。读完你既能在本地跑起这个可交互的排版测试台也能在真实项目中独立配置和定制 prose 排版。1. 沙箱是什么一个可交互的 prose 排版试验台仓库中的 sandbox/prose/README.md 描述了一个Playground forpandacss/preset-typography——它不是一个演示静态效果的示例页而是一个可交互验证 prose 排版行为的试验台。技术栈组合如下见 sandbox/prose/package.jsonTanStack Routertanstack/react-router提供路由用于在/主页面与/not-prose隔离演示页之间跳转Vite React提供开发环境与 JSX 渲染pandacss/preset-typography提供proserecipe 与语义颜色 tokenpandacss/dev pandacss/vite完成 Panda 的代码生成与样式编译。沙箱的入口路由位于 sandbox/prose/src/routes/index.tsx实际界面由 sandbox/prose/src/components/Playground.tsx 渲染。整个界面刻意保持极简一个吸顶头部含尺寸切换、深色模式、最大宽度开关、not-prose 演示链接正文是一篇使用MarkdownSample /模拟的富文本文章。设计意图这个沙箱不是给你看一个好看的博客样式而是给你一个切换开关就能观察每个排版特性实际效果的验证环境——换尺寸、切深色、关宽度、开隔离四种行为都能即时看到输出变化。2. 运行沙箱原文档给出了两条命令须在仓库根目录执行pnpm --filter sandbox-prose install pnpm --filter sandbox-prose devdev脚本的定义在 sandbox/prose/package.json 中dev: pnpm --filter pandacss/preset-typography build pnpm codegen vite, build: pnpm --filter pandacss/preset-typography build pnpm codegen tsc vite build, codegen: panda codegen, cssgen: panda cssgen注意两个细节由于沙箱通过workspace:*引用本地包pandacss/dev、pandacss/preset-typography等均为 workspace 依赖启动前会先pnpm --filter pandacss/preset-typography build构建排版预设的产物再执行panda codegen生成styled-system/目录最后才由 Vite 启动开发服务器。因此codegen产出的styled-system/recipes与styled-system/css是沙箱源码如Playground.tsx中的import { prose } from ../../styled-system/recipes直接依赖的编译产物属于仓库内生成的中间文件。3. 打开应用后可以验证的四个排版行为原文档列出打开页面后的四组交互项它们分别对应 prose 预设中最核心的四类能力3.1 Size —— 五档字号切换SM / MD / LG / XL / 2XL工具栏提供sm | md | lg | xl | 2xl五个按钮点击后通过prose({ size })动态切换 recipe 变体见 sandbox/prose/src/components/Playground.tsxarticle className{cx(prose({ size }), css({ mx: auto, ...(fullWidth ? { maxW: none } : {}) }))}而 recipe 的尺寸变体之所以能被staticCss预先全部生成来自 sandbox/prose/panda.config.ts 的静态配置staticCss: { recipes: { prose: [{ size: [sm, md, lg, xl, 2xl] }], }, },源码层面createProseSize的逻辑极其简单——一个尺寸只是根元素上的一个字号其余一切都靠em相对缩放见 packages/preset-typography/src/styles.tsconst rootFontSizes: RecordProseSize, string { sm: sm, md: md, lg: lg, xl: xl, 2xl: 2xl, } export function createSizeStyles(size: ProseSize): ProseStyleParts { return { root: { fontSize: rootFontSizes[size] }, elements: {} } }而根元素字号使用的正是 Panda 的fontSizes.sm/md/lg等 token。md是默认档位由 recipe 的defaultVariants指定见 packages/preset-typography/src/recipe.ts。3.2 Dark —— 深色模式切换_dark语义 token深色开关通过切换根节点的.darkclass 实现。沙箱在 sandbox/prose/src/lib/theme.ts 中封装了applyDarkClass与readDarkPreference初次进入时读取系统偏好之后点击按钮即在document.documentElement上增删.darkclass。Panda 的_dark条件会命中这个.dark作用域而 prose 的颜色恰好全部是带_dark值的语义 token。例如默认预设中prose.body{colors.neutral.700}亮色/{colors.neutral.300}暗色prose.heading{colors.neutral.900}/{colors.neutral.100}这正是原文档所说toggles the.darkclass (semantic token_darkvalues)的完整含义深色模式下你无需任何额外代码文章的颜色体系会自动跟着语义 token 的_dark分支走。沙箱页面的页面级底色body的bg: white/_dark: bg: neutral.950也是通过 sandbox/prose/panda.config.ts 的globalCss配置的保证切换时有完整的明暗对比反馈。3.3 Max width off —— 移除默认的sizes.prose宽度上限打开后正文会从默认的maxWidth: prose变为不限制宽度...(fullWidth ? { maxW: none } : {}),这里的默认宽度prose来自 packages/preset-typography/src/styles.ts 的 base 样式root: { color: color(prefix, body), maxWidth: prose, },也就是读取 Panda 的sizes.prosetokenPanda 预设在sizes中提供了prose这一阅读宽度刻度。这个开关适合验证当容器宽度变化时prose 的排版节奏行高、块间距是否依然协调——答案正是下一节的em缩放机制。3.4 /not-prose —— 白名单式的内容隔离岛顶部导航有一个not-prose demo链接指向独立路由 sandbox/prose/src/routes/not-prose.tsx用于演示如何让某个内容区域从 prose 样式中退出。它对应预设选项notProse: true沙箱配置中已开启见 sandbox/prose/panda.config.tstypographyPreset({ notProse: true, }),4. 排版体系的两大支柱em 缩放与节奏变量从沙箱里能直观感受到的无论换多大字号排版都依然协调在源码中有精确的设计这部分是 prose 预设的核心实现值得单独展开。4.1 全 em 缩放让文章随容器缩放pandacss/preset-typography的设计原则是一个尺寸 根元素一个字号其余元素全部用em相对它缩放。标题、行距、间距、代码块、表格、图片注释的尺寸均为根字号的倍数。以标题为例见 packages/preset-typography/src/styles.tsh1: { fontSize: 2.25em, lineHeight: 1.25, marginBlockStart: 0 }, h2: { fontSize: 1.5em, lineHeight: 1.375, marginBlockStart: flowTimes(2.4, 1.5) }, h3: { fontSize: 1.25em, lineHeight: 1.375, marginBlockStart: flowTimes(1.6, 1.25) }, h4: { fontSize: 1.125em, lineHeight: 1.375, marginBlockStart: flowTimes(1.2, 1.125) },em有一个陷阱嵌套元素上的em会以自身字号为参照累积计算。为了让--prose-flow里的em始终落在正文级而不是元素级源码用calc做了补偿见 packages/preset-typography/src/styles.ts 中的注释与flowTimes实现// em in the flow var resolves per element, so divide by the elements ratio to stay in body-ems. const flowTimes (bodyEms: number, ratio 1) calc(${flow.ref} * ${round(bodyEms / ratio)})例如 h2 的间距2.4 个正文 em ÷ 1.5h2 自身比例 1.6于是得到calc(var(--prose-flow) * 1.6)——测试用例 packages/preset-typography/tests/preset.test.ts 中明确断言了这个值。预设甚至有一条专门测试来保证没有任何元素使用rem、px或字号 token因此文章会随容器缩放test(no element uses rem, px, or a size token, so the article scales with its container, () { // 遍历所有 base 样式若 fontSize/lineHeight/margin/padding 中出现 rem、px 或 spacing/fontSizes token 即视为违规 expect(offenders).toEqual([]) })这意味着把prose放进一个更小的容器比如侧边栏整篇文章排版会整体等比缩小这正是原文档a prose inside a smaller container scales down with it的实际来源。4.2 节奏变量--prose-flow与--prose-leading整个正文的垂直节奏由根元素上的两个 CSS 自定义属性驱动见 packages/preset-typography/src/styles.tsroot[leading.name] 1.625 // --prose-leading全局行高 root[flow.name] 1.25em // --prose-flow块与块之间的间距--prose-leading控制行高作用于根与pre等块级代码--prose-flow控制段落、列表、引用、标题、表格等元素之间的间距。这两个变量的真正价值是可覆写在包裹层上用css()覆盖即可整体收紧或放宽一篇文章的节奏而不必逐个元素调整。预设 READMEpackages/preset-typography/README.md给出了用法article className{cx(prose(), css({ --prose-leading: 1.5, --prose-flow: 1em }))} /若把 recipe 改名为article变量名也会随之变成--article-flow/--article-leading测试用例对此有断言这样在同一页面中可以并排使用多套互不干扰的排版节奏。5. 颜色体系语义 token 驱动的明暗双模式prose 的所有颜色都不是写死的十六进制值而是以colors.prefix.*命名的语义 token每个 token 都带base与_dark两个分支。默认生成的完整清单如下来源packages/preset-typography/src/semantic-tokens.tsToken key用途亮色暗色body正文文本neutral.700neutral.300headingh1–h4、表头neutral.900neutral.100lead.lead引导段neutral.600neutral.400link链接文字neutral.900neutral.100linkDecoration链接下划线neutral.300neutral.600boldstrong / bneutral.900neutral.100counter有序列表标记neutral.500neutral.400bullet无序列表标记neutral.300neutral.600hrBorder水平线、kbd 边框neutral.200neutral.700quote引用文字neutral.900neutral.200quoteBorder引用左边框neutral.200neutral.700captionfigcaptionneutral.500neutral.400kbd键盘文本neutral.900neutral.100code行内代码文字neutral.900neutral.100codeBg行内代码背景neutral.100neutral.800preCode代码块文字neutral.800neutral.200preBg代码块背景neutral.100neutral.800thBorder表头/表尾边框neutral.300neutral.600tdBorder表体行边框neutral.200neutral.700对应到 recipe 中各处样式直接引用这些语义 key见 packages/preset-typography/src/styles.ts链接使用prose.link并单独用prose.linkDecoration控制下划线颜色与粗细1px下划线 0.2em的textUnderlineOffset引用块刻意不斜体fontStyle: normal左边框为2px宽行内代码是胶囊样式prose.codeBg背景 sm圆角而pre code会被完全重置为透明背景与继承字体表格行间分隔用tbody tr tr的上边框而非首行边框避免流式追加内容时产生双重边框——这些细节均有对应测试断言。如需覆盖某个颜色只需在项目配置中theme.extend.semanticTokens覆写对应 keyexport default defineConfig({ presets: [pandacss/preset-panda, typographyPreset()], theme: { extend: { semanticTokens: { colors: { prose: { link: { value: { base: {colors.blue.700}, _dark: {colors.blue.300} } }, }, }, }, }, }, })如果希望完全不使用预设的默认颜色可设置semanticTokens: { enabled: false }此时需要按上面的表在自定义 prefix 下自行补齐全部 key——预设源码会据此跳过语义 token 的注入见 packages/preset-typography/src/index.ts 的shouldIncludeSemanticTokens判断与测试用例。6. 预设选项全解从 name 到 notProsetypographyPreset()是一个工厂函数类型定义位于 packages/preset-typography/src/types.ts完整选项如下typographyPreset({ name: prose, // recipe 导出名、默认类名、默认 token 前缀 className: prose, // 仅当需要与 name 不同的类名时设置 sizes: [sm, md, lg, xl, 2xl], // 要生成的尺寸变体 defaultSize: md, // 调用处省略 size 时的默认值 notProse: true, // true 使用 not-prose 类传字符串则用自定义类名 semanticTokens: { // enabled: false, // 设为 false 跳过默认颜色 token prefix: prose, // 语义颜色前缀 colorPalette: neutral, // 默认取色的 50–950 色板 }, })各选项的行为在 packages/preset-typography/src/recipe.ts 中有清晰的解析逻辑sizes为空数组时直接抛错include at least one size variantdefaultSize不在sizes中也会抛错defaultSize省略时优先取md否则取第一个尺寸className缺省时等于namesemanticTokens.prefix缺省时等于name再退到常量prose见 packages/preset-typography/src/constants.tsname一旦改为article生成的 recipe 就只剩article原prose消失语义 token 前缀与 CSS 变量名--article-*同步变更——测试用例 packages/preset-typography/tests/preset.test.ts 完整覆盖了这些组合。notProse 的底层实现:where():not()白名单notProse: true的实现非常巧妙它生成的选择器用:where()包裹目标元素、再用:not()排除 opt-out 区域见 packages/preset-typography/src/styles.ts 的nestSelectorparts.map((part) :where(${part}):not(:where([class~${notProseClass}],[class~${notProseClass}] *))).join(, )即匹配所有part元素但排除自身带not-prose类、或位于带not-prose类的祖先内部的所有元素。同时:where()使这些选择器的特异性恒为零任何用户自己的样式都能轻松覆盖不必依赖更深的嵌套去比拼权重。测试用例验证了开启后recipe.base中不再出现裸的 a选择器而会出现包含:where(a)与not-prose的隔离选择器。配合staticCss预生成notProse的 class 名也可自定义为任意字符串如skip-prose适合与内容管理系统CMS产出的既有 class 体系衔接。7. 应用场景与最佳实践小结7.1 典型落地场景Markdown 博客正文div className{prose({ size: lg })} dangerouslySetInnerHTML{{ __html: html }} /一行即可让 markdown 渲染出的任意 HTML 拥有完整排版CMS 富文本富文本编辑器输出的 HTML 结构通常不可控prose通过元素选择器覆盖h1–h4、p、ol/ul、blockquote、table、figure/figcaption、kbd、pre/code等完整元素集合深色模式文章页语义 token 自带的_dark分支让整篇文章在.dark下自动切换配色无需重复编写任何暗色样式组件内部的富文本片段全em缩放让prose可以嵌进任意尺寸的容器中仍保持协调的排版。7.2 常用定制组合需求做法只要两档字号sizes: [sm, lg]并让defaultSize属于sizes改类名避免与现有样式冲突name: article, className: rich-text内容区退出排版notProse: true在内容上添加classnot-prose整体放宽/收紧节奏在包裹层覆盖--prose-flow与--prose-leading换一套配色semanticTokens: { colorPalette: blue }或覆写具体 key完全自绘颜色semanticTokens: { enabled: false }并自行补齐全部 key7.3 一处迁移注意如果你是从旧的pandacss-preset-typography迁移而来见 packages/preset-typography/README.md 的迁移说明包名改为pandacss/preset-typography默认尺寸由base改为md若不需要默认配色用semanticTokens: { enabled: false }关闭。8. 进一步阅读想深入源码与验证细节可以按以下路径继续探索当前仓库预设完整文档packages/preset-typography/README.md预设工厂与导出packages/preset-typography/src/index.tsrecipe 构造与选项校验packages/preset-typography/src/recipe.ts排版样式与 notProse 选择器packages/preset-typography/src/styles.ts语义颜色 tokenpackages/preset-typography/src/semantic-tokens.ts选项类型定义packages/preset-typography/src/types.ts行为测试用例packages/preset-typography/tests/preset.test.ts沙箱配置与组件sandbox/prose/panda.config.ts 、sandbox/prose/src/components/Playground.tsx赞分享前端构建工具开发工具【免费下载链接】panda Universal, Type-Safe, CSS-in-JS Framework for Design Systems ⚡️项目地址https://gitcode.com/gh_mirrors/pa/panda点击查看免费下载相关推荐Rerun Properties 与 Segment 表录制级元数据的写入、查询与过滤实战指南Rerun Properties 与 Segment 表录制级元数据的写入、查询与过滤实战指南 Properties属性是 Rerun 中录制recor前端构建工具开发工具Panda CSS Preset 创建实战将设计系统翻译为类型安全的 Token 与 RecipePanda CSS Preset 创建实战将设计系统翻译为类型安全的 Token 与 Recipe 在 Panda CSS 项目 README https:前端构建工具开发工具Nuxt UI 排版指南用 Markdown 列表与表格组织内容Prose Lists TablesNuxt UI 排版指南用 Markdown 列表与表格组织内容Prose Lists Tables 本篇技术指南聚焦 Nuxt UI 文档中「Lis前端UI组件上一篇distribution-is-all-you-need可视化教程用Python绘制高斯分布与t分布的概率密度曲线下一篇三分钟打造专业级foobar2000音乐播放器界面foobox美化方案终极指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考