Claude Code Artifact 页面创作与 HTML 骨架契约:从设计技能加载到发布时重置样式的完整规范
Claude Code Artifact 页面创作与 HTML 骨架契约:从设计技能加载到发布时重置样式的完整规范
Artifact 是 Claude Code 中一种可发布、可交互的页面产物。本指南基于 Claude Code 系统提示词仓库中的工具描述文档 tool-description-artifact-page-authoring-and-html-skeleton-app-wording.md,完整拆解 Claude 在创作 Artifact 页面时必须遵守的两层契约:写作前必须加载 Artifact 设计技能,以及发布时由查看器包裹的 HTML 骨架与最小重置样式。读完本文,你将理解 Artifact 页面的标准创作流程、骨架边界、安全区(safe-area)适配规则、可见性切换约定,并掌握如何结合仓库内相邻的响应式、CSP、主题等契约写出合规的页面。
这份工具描述在 Claude Code 系统提示词体系中的位置
本仓库(claude-code-system-prompts)镜像了 Claude Code 各版本的系统提示词、27 个内置工具描述、子代理提示词(Plan / Explore / Task)以及实用提示词。本关联文档属于"工具描述(Tool Description)"类,其 frontmatter 声明如下:
- name:
Tool Description: Artifact page authoring and HTML skeleton (app wording) - description:面向应用(app)措辞的、要求在创作前加载 Artifact 设计技能、并针对查看器提供的 HTML 骨架编写页面内容的规范
- ccVersion:
2.1.271(随 Claude Code 版本更新的版本号) - variables:声明了
ARTIFACT_DESIGN_SKILL_NAME、IS_WORKSHOP_SUPPORTED、WORKSHOP_SKILL_NAME、ARTIFACT_DIAGRAMMING_SKILL_NAME、IS_ARTIFACT_QUICKSTART_ENABLED、ARTIFACT_QUICKSTART_GUIDANCE六个模板变量
这些 variables 由 Claude Code 运行时在注入提示词时填充,例如 ${ARTIFACT_DESIGN_SKILL_NAME} 会被替换为当前环境中实际的设计技能名称。理解这一点很重要:文档正文中所有 ${...} 占位符都不是静态文本,而是"按当前会话能力动态决定"的配置点。与其同属一个系列的文档还包括 tool-description-artifact-html-document-skeleton.md(同一契约的非 app 措辞版本)与 tool-description-artifact-design-skill-loading-guidance-app-wording.md(设计技能加载规则的独立版本),可以互为印证。
写作前的强制门槛:先加载 Artifact 设计技能
文档的第一条规则是一条硬性前置条件:
在写文件之前,Claude 必须加载
${ARTIFACT_DESIGN_SKILL_NAME}技能——即使是某个技能让 Claude 去写的.md文件也不例外。
这条约束有四个关键点:
- 适用对象无差别:无论是写 HTML 页面还是写 Markdown 文件,只要目标是 Artifact,都必须在落笔前加载设计技能。设计技能中承载了完整的页面契约——从创作格式(HTML,或仅在已加载技能要求时才使用 Markdown)、标题、库引用、存储方式、尺寸限制、布局、主题到图标。
- 设计技能决定设计投入:该技能"设定了请求应获得多少设计努力"(how much design effort the request deserves)。也就是说,设计深度不是由 Claude 自行揣摩的,而是由技能按请求类型分派的。
- 格式规则与设计分离:文档明确"上面的 Format 规则负责定格式",即最终用 HTML 还是 Markdown 由 Format 规则裁定,而设计技能负责页面设计的深度与质量。
- 禁止用 Markdown 绕过设计流程:文档原句 "Claude never writes Markdown to get around the design pass"——Claude 绝不能为了规避设计环节而改写成 Markdown。这是对"格式降级逃避设计"行为的明确禁止。
唯一的例外:Workshop 文档
当 ${IS_WORKSHOP_SUPPORTED} 为真时,存在一个例外路径:来自 ${WORKSHOP_SKILL_NAME} 技能的 workshop 文档自带设计(carries its own design)。此时 Claude 跳过 ${ARTIFACT_DESIGN_SKILL_NAME},改为加载 ${ARTIFACT_DIAGRAMMING_SKILL_NAME},专门用于模板页中的图表绘制。换句话说,workshop 模板的设计是预先定好的,Claude 只需要为其配图。仓库中 skill-artifact-diagramming.md 即是该图表技能的定义文件。
快速启动(Quickstart)条件注入
当 ${IS_ARTIFACT_QUICKSTART_ENABLED} 为真时,文档会在该位置追加 ${ARTIFACT_QUICKSTART_GUIDANCE} 的内容。这说明整套提示词是"按能力裁剪"的:快速启动流程开启时,Claude 会额外获得一份快速启动指引,未开启则完全不注入,避免对不需要的用户造成噪音。
创作流程:写文件,再以路径调用 Artifact
完成设计技能加载后,文档给出标准的创作链路:
- 写文件:Claude 通过 Write/Edit 把页面内容写入一个文件。
- 调用 Artifact 并传入文件路径:Claude 随后调用 Artifact 工具,把该文件路径作为参数传入,由发布管线完成骨架包裹与发布。
- scratchpad 目录规则:当系统提示词列出了 scratchpad 目录、且用户没有指定其他位置时,该文件应放入 scratchpad 目录。这是为了让 Claude 维护的本地文件与已发布页面之间保持可追踪的关系——这一点在运行时能力契约中还会进一步体现(见后文"自保存页面与本地版本冲突")。
发布时包裹的 HTML 骨架:作者只写内容,不写外壳
文档的 "Skeleton" 部分定义了发布时的包裹行为:
发布时,文件会被包裹进一个
<!doctype html>…<head>…</head><body>骨架中,因此 Claude 直接编写页面内容即可,以它自己的<title>和<style>开头,不再写<html>、<head>或<body>标签。
这与常规前端开发习惯形成鲜明对照。作者侧的输入文件大致是这个样子:
<title>今日数据概览</title>
<style>
/* 页面自己的样式 */
</style>
<!-- 页面主体内容直接开始 -->
<h1>今日数据概览</h1>
<p>…</p>
而发布后查看器实际得到的页面是:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<style>
/* 最小重置样式(由发布管线注入) */
</style>
<title>今日数据概览</title>
<style>
/* Claude 自己的样式 */
</style>
</head>
<body>
<!-- Claude 的页面内容 -->
</body>
</html>
关键点:骨架的 <head> 中只承载字符集、viewport meta(含 viewport-fit=cover)以及一小段重置样式。作者不要试图自己写 <!DOCTYPE>、<html>、<head>、<body>,否则会与发布管线注入的骨架冲突。文档在 tool-description-artifact-html-document-skeleton.md 中给出了完全一致的说明,可以作为本规则的独立佐证。
最小重置(minimal reset)契约逐条解读
骨架头部注入的重置样式虽然"小",但每一条都有明确的设计意图。综合本关联文档与 tool-description-artifact-html-document-skeleton.md,重置契约包含以下五条:
| 规则 | 具体内容 | 设计意图 |
|---|---|---|
color-scheme |
浅色 color-scheme |
让表单控件、滚动条等原生 UI 在浅色模式下保持一致外观 |
:root 安全区内边距 |
根元素顶部与底部各填充手机的安全区插入量(safe-area insets) | 刘海屏/挖孔屏下内容不被系统 UI 遮挡 |
body 基础排版 |
零外边距、14px 系统字体、米白(off-white)底色 | 提供一致的阅读基线与页面底色 |
| 图片约束 | img{max-width:100%} |
防止大图溢出视口,是响应式契约的基础 |
| 隐藏元素 | [hidden]{display:none!important} |
保证 hidden 属性的语义在任何情况下都生效 |
为什么 [hidden] 要用 !important
文档特别强调:切换可见性要用 el.hidden,而不是 style.display。原因是骨架已声明 [hidden]{display:none!important},任何元素只要带有 hidden 属性就必然不可见,不会被页面自己的 display 规则意外覆盖。因此正确的做法是:
// 正确:切换 hidden 属性
el.hidden = true; // 隐藏
el.hidden = false; // 显示
// 错误:直接改 style.display,会绕过 [hidden] 契约
el.style.display = 'none';
这条约定保证了"隐藏"语义始终来自属性而非行内样式,使骨架的重置规则与页面脚本之间不会互相踩踏。
保留 :root 的安全区内边距
文档用强调语气要求 保留(keep):root 的 padding——Claude 不得为了追求"无内边距的沉浸式布局"而把根元素的安全区 padding 清零。原因在于:安全区内边距是骨架布局的一部分,固定条和吸顶头都要在它的基础上叠加计算。
安全区适配:固定条与吸顶头的正确写法
这是本文档最具体的实战规则,值得单独成节。文档原文:
Claude keeps that
:rootpadding: a bar fixed to the top or bottom addsenv(safe-area-inset-top, 0px)orenv(safe-area-inset-bottom, 0px)to its own padding, and a sticky header usestop: env(safe-area-inset-top, 0px), not0.
拆解为两种场景:
场景一:position: fixed 的顶栏/底栏。固定定位的元素脱离文档流,:root 的 padding 对它不生效,因此它必须在自己身上叠加安全区:
.top-bar {
position: fixed;
top: 0;
/* 在自身 padding 上叠加顶部安全区,而不是 top: env(...) */
padding-top: env(safe-area-inset-top, 0px);
}
.bottom-bar {
position: fixed;
bottom: 0;
padding-bottom: env(safe-area-inset-bottom, 0px);
}
场景二:position: sticky 的吸顶头。sticky 元素仍在文档流中,:root 的 padding 会把它往下推,但滚动时它需要贴住视口顶部,此时要用 top 而不是 padding:
.sticky-header {
position: sticky;
/* 必须用 env(),而不是 0;否则会贴进刘海区域 */
top: env(safe-area-inset-top, 0px);
}
注意两处都使用了 env(safe-area-inset-*, 0px) 的带回退值写法——在不支持安全区的桌面浏览器上回退为 0px,页面依然正常。这份规范性描述在 tool-description-artifact-html-document-skeleton.md 中也有同义表述("a bar fixed to the top or bottom stays at 0 and adds … to its own padding"),两处文档相互印证。
与骨架配套的相邻契约:响应式页面
骨架只是壳,页面内容本身还受一组相邻契约约束。与创作最直接相关的是响应式契约,定义于 tool-description-artifact-responsive-page-contract.md,要点如下:
- 手机宽度必须可用(约 400px),且页面主体永不横向滚动;
- 任意宽度下保持至少 16px 的侧边距:一次性在
body或唯一外层包裹元素上设置侧 padding,该元素的垂直 padding 用padding-block书写,禁止用会清空侧边的padding简写; - 使用相对单位;flex/grid 行在窄屏下换行或堆叠为一列;
- 承载正文、代码或表格的 flex/grid 子项设置
min-width: 0,让长内容在内部换行或滚动,而不是把页面撑宽; - 图片与
aspect-ratio盒子设置max-width: 100%,任何元素的min-width不得宽于屏幕; - 只有表格、图表和代码块可以更宽,且各自放在独立的
overflow-x: auto容器中。
这条契约与骨架中的 img{max-width:100%} 是一体的:骨架提供图片约束的兜底,响应式契约则规定了布局层面的结构性要求。作者在写 <style> 时,应把这两层同时纳入考虑。
骨架之外:CSP、存储、尺寸、主题与图标
页面发布后运行在查看器的沙箱中,因此还有一组"实现要求"契约,记录在 tool-description-artifact-page-implementation-requirements-app-wording.md 中,与本文档的创作规则形成完整闭环:
- 外部资源白名单:脚本只允许来自 cdnjs.cloudflare.com(首选)、cdn.jsdelivr.net/npm/、unpkg.com、cdn.tailwindcss.com、code.jquery.com 五个主机,且通过
<script src="https://cdnjs.cloudflare.com/ajax/libs/<lib>/<exact version>/<file>">固定精确版本、在使用它的内联脚本之前引入;样式表仅允许 fonts.googleapis.com 及其字体文件 fonts.gstatic.com;其余一切外部请求(含库自身的运行时 fetch)都会被 CSP 静默拦截,因此所有其他 CSS/JS 必须内联,资源以data:URI 嵌入; - 浏览器存储:
localStorage、sessionStorage、IndexedDB 按 Artifact 源(origin)生效且只存在于当前查看器的浏览器中,可能为空或抛异常,必须 try/catch 包裹,且只用于"记住标签页、未发送草稿"这类单查看器便利;需要可靠持久化、跨查看器共享或由 Claude 回读的状态应使用运行时能力(runtime capability); - 尺寸:渲染后的页面必须不超过
${MAX_ARTIFACT_BYTES}字节(含内嵌 data: URI); - 主题感知:页面跟随查看器主题渲染,根元素显式
data-theme="dark"/data-theme="light",默认 system 设置不盖章、只保留prefers-color-scheme;浅色调色板定义为裸:root上的令牌,深色块在:root:not([data-theme="light"])与:root[data-theme="dark"]两处守卫下覆盖,保证切换器在两个方向都生效;任何颜色不得只在 media 或[data-theme]块内定义,且body必须有显式背景色; - 图标:首次发布时必须提供一个简短通用词作为
icon(如"chart"、"calendar"、"recipe"),用于浏览器标签页图标,不得使用产品/品牌名、emoji 或标记语言;重新部署时省略icon,仅当用户明确要求时才传新的。
这些约束解释了为什么骨架的 <head> 如此精简:外部资源受限,页面必须自给自足,骨架只需保证最小的可运行基线。
运行时能力与自保存页面:创作的后续闭环
本仓库 中的运行时能力文档进一步说明:已发布页面可以通过 capabilities 输入声明能力——读取用户的实时/已连接数据、记住访客行为(投票、签到表、清单、就地编辑的文档)、跨查看器共享状态、感知访客、向 Claude 提问、存储用户添加的文件、或给访客提供可保存的文件。其规则与本创作契约直接衔接:
- 只要这些能力会让页面更有用,Claude 就必须在写作前加载
${ARTIFACT_CAPABILITIES_SKILL_NAME}技能,且总是先于传递capabilities或编写任何window.claude.*运行时代码之前——这与本文档"写作前先加载设计技能"是同一套"先加载技能再动手"的模式; - 能保持状态的能力优先于浏览器存储用于该状态,
localStorage降级为单查看器便利设施; - 重复部署时省略
capabilities字段保留已有能力,{}则清空; - 自保存页面会造成本地版本冲突:就地编辑的文档会保存自身的新版本,使 Claude 的本地文件过期,Claude 需要重新读取页面、合并改动并重新发布。
仓库中的 data-artifact-decision-component-html-skeleton.md 与 skill-artifact-components.md 展示了这套契约在实践中的落地形态:可复用组件以"固定脚本 + 雕刻样式 + 带不变量注记的标记骨架 + JSON 数据岛"的形式交付,发布校验器通过 sha256 哈希锁定脚本字节,任何编辑、重排或格式化都会以 script-not-blessed 拒绝发布;JSON 岛(ws-decisions)每页只能有一个,其 id 拼写不得在页面字节中出现第二次。可见,"骨架 + 契约 + 校验"是一套完整的工程体系,而非零散建议。
小结:创作 Artifact 页面时的完整检查清单
综合本关联文档及其配套契约,创作一个 Artifact 页面时应依次满足:
- 写作前:加载
${ARTIFACT_DESIGN_SKILL_NAME}(workshop 模板例外,改加载图表技能;quickstart 开启时按注入指引执行);如需运行时能力,先加载能力技能; - 写作时:以
<title>和<style>开头直接写内容,不写<html>/<head>/<body>/DOCTYPE;把文件写入 scratchpad(若系统提示词列出且用户未指定其他位置),再以路径调用 Artifact; - 样式上:遵守重置契约——保留
:root安全区内边距、零 body 外边距 + 14px 系统字体 + 米白底色、img{max-width:100%};切换可见性用el.hidden;固定条在自身 padding 叠加env(safe-area-inset-*, 0px),吸顶头用top: env(safe-area-inset-top, 0px); - 布局上:遵守响应式契约——16px 侧边距、
padding-block、min-width:0、横向滚动只存在于表格/图表/代码块的overflow-x:auto容器内; - 资源与能力上:只使用 CSP 白名单外部资源,其余内联或
data:URI;存储按"能力优先、localStorage 兜底";页面 ≤ 尺寸上限;主题令牌化并保证切换器双向生效;首次发布带通用词icon。
这套规则确保了不同 Claude Code 版本、不同会话能力下产出的 Artifact 页面行为一致、可校验、可交互,也正是本关联文档在系统提示词体系中承担的角色——它是一份写给模型的、精确到 CSS 属性的创作契约。