内联响应式图片与canvas,断开服务后检查缺图
本页展示随包原生输入和验收参考。目标产品运行状态:未运行。表格与图片不代表产品已经生成的结果。
input.csv / practice-data.json
本课实际输入字段
| asset | src | srcset | labels | values | capture | value | filter |
|---|---|---|---|---|---|---|---|
| cover | /cover-640.png | /cover-1280.png 1280w | |||||
| canvas | ["Mon", "Tue", "Wed"] | [12, 18, 9] | |||||
| viewport | 1280x800 | 本周 |
使用快照脚本
reference.csv:作者验收映射,不是目标API回包
| asset | expected | check |
|---|---|---|
| cover | data URI or resolved inline candidate | |
| canvas | serialized image with three bars | |
| visuals remain | server stopped |
规则与输入文件原文
{
"inputRows": [
{
"asset": "cover",
"src": "/cover-640.png",
"srcset": "/cover-1280.png 1280w"
},
{
"asset": "canvas",
"labels": [
"Mon",
"Tue",
"Wed"
],
"values": [
12,
18,
9
]
},
{
"capture": "viewport",
"value": "1280x800",
"filter": "本周"
}
],
"referenceRows": [
{
"asset": "cover",
"expected": "data URI or resolved inline candidate"
},
{
"asset": "canvas",
"expected": "serialized image with three bars"
},
{
"check": "server stopped",
"expected": "visuals remain"
}
],
"invalidRows": [
{
"asset": "cover",
"srcset": "http://localhost:5173/missing.png 1280w"
},
{
"asset": "canvas",
"inlineCanvas": false,
"error": "blank canvas after script removal"
}
],
"notes": [
"全部输入为作者自制教学资料,不含真实客户或账号。",
"referenceRows是校验基准,不是目标模型预测或识别结果;targetProduct=not_run。"
],
"files": {
"input.json": "[\n {\n \"asset\": \"cover\",\n \"src\": \"/cover-640.png\",\n \"srcset\": \"/cover-1280.png 1280w\"\n },\n {\n \"asset\": \"canvas\",\n \"labels\": [\n \"Mon\",\n \"Tue\",\n \"Wed\"\n ],\n \"values\": [\n 12,\n 18,\n 9\n ]\n },\n {\n \"capture\": \"viewport\",\n \"value\": \"1280x800\",\n \"filter\": \"本周\"\n }\n]\n",
"reference.json": "{\n \"identity\": \"作者验收参考,非模型返回\",\n \"rows\": [\n {\n \"asset\": \"cover\",\n \"expected\": \"data URI or resolved inline candidate\"\n },\n {\n \"asset\": \"canvas\",\n \"expected\": \"serialized image with three bars\"\n },\n {\n \"check\": \"server stopped\",\n \"expected\": \"visuals remain\"\n }\n ]\n}\n",
"invalid.json": "{\n \"identity\": \"作者构造负例,非实际错误回包\",\n \"rows\": [\n {\n \"asset\": \"cover\",\n \"srcset\": \"http://localhost:5173/missing.png 1280w\"\n },\n {\n \"asset\": \"canvas\",\n \"inlineCanvas\": false,\n \"error\": \"blank canvas after script removal\"\n }\n ]\n}\n",
"case.md": "# Stitch静态HTML快照:内联响应式图片与canvas,断开服务后检查缺图\n\nStitch静态HTML快照解决“上传时正常、离线打开缺图”的问题。本课同时处理srcset图片与canvas图表,验证它确实是可独立打开的静态输入。\n\n## 准备两类媒体\n\n本地样本放一张带srcset的活动图和一个canvas柱图。\n\n为二者记录实际像素和文字说明,不把纯色占位块当图表。\n\n## 固定视口和状态\n\n选择1280x800、筛选项“本周”,等待图片加载。\n\n截图状态和保存状态必须相同,避免快照拿到默认空图。\n\n## 使用快照脚本\n\n读取官方extract-static-html的snapshot.ts参数,指定输出文件。\n\ncanvas需启用--inline-canvas,普通DOM提取不会自动保存canvas像素。\n\n## 检查资源内联\n\n检查img src与srcset、source srcset是否已内联或清除失效项。\n\n保留一个故意未内联的负例,看浏览器是否退回错误网络地址。\n\n## 断开本地服务复查\n\n只在作者练习副本停止服务后打开standalone.html。\n\n外部字体可能仍依赖网络,单独记录,不能一概宣称所有资源全离线。\n\n## 比对图表数据\n\n将快照中的三根柱子与原始值12、18、9对应。\n\n图像保留不代表图表仍可交互或筛选,应明确静态边界。\n\n## 交付静态输入\n\n保存HTML、资源检查表和在线/断开服务对照。\n\n后续上传Stitch需另行实际执行,不把文件生成等同云端导入成功。\n\n身份:输入与参考为作者材料;localCli有实测记录时仅证明对应CLI运行,目标云端与模型推理未执行。\n",
"cover-source.svg": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"1200\" height=\"800\"><rect width=\"1200\" height=\"800\" fill=\"#f7f4ec\"/><rect x=\"60\" y=\"60\" width=\"1080\" height=\"680\" rx=\"24\" fill=\"#184a45\"/><text x=\"120\" y=\"230\" fill=\"white\" font-family=\"Arial,sans-serif\" font-size=\"80\">FIELD KIT</text><text x=\"120\" y=\"370\" fill=\"white\" font-family=\"Arial,sans-serif\" font-size=\"72\">¥68</text><text x=\"120\" y=\"650\" fill=\"white\" font-family=\"Arial,sans-serif\" font-size=\"34\">Cancel 24 hours before start</text></svg>",
"snapshot-source.html": "<!doctype html><html lang=\"zh-CN\"><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"><title>快照媒体原稿</title><style>body{font:16px/1.6 Arial,sans-serif;background:#f7f4ec;color:#183b39;margin:32px;max-width:1100px}h1{font-size:32px}article{padding:24px;border:1px solid #cbd4cc;background:white;margin:16px 0}button{background:#184a45;color:white;padding:12px 20px;border:0;border-radius:8px}table{border-collapse:collapse;width:100%}th,td{padding:10px;border:1px solid #cbd4cc;text-align:left}pre{white-space:pre-wrap;overflow-wrap:anywhere}</style><h1>本周活动</h1><img width=\"480\" src=\"cover-640.png\" srcset=\"cover-1280.png 1280w\" alt=\"Field Kit票券\"><canvas width=\"480\" height=\"280\" id=\"bars\"></canvas><script>const c=document.querySelector(\"canvas\").getContext(\"2d\");c.fillStyle=\"#184a45\";[12,18,9].forEach((v,i)=>{c.fillRect(40+i*140,250-v*10,80,v*10);c.fillText([\"Mon\",\"Tue\",\"Wed\"][i],40+i*140,270)});</script></html>",
"snapshot-command.txt": "npx tsx <official-skill-dir>/scripts/snapshot.ts --url http://localhost:5173/snapshot-source.html --output standalone.html --viewport 1280x800 --inline-canvas\n先将原创cover-source.svg实际渲染为640和1280宽PNG,不可只改扩展名。\n"
}
}应当保留的约束
| asset | expected | check |
|---|---|---|
| cover | data URI or resolved inline candidate | |
| canvas | serialized image with three bars | |
| visuals remain | server stopped |
故意构造的错误样例
| asset | srcset | inlineCanvas | error |
|---|---|---|---|
| cover | http://localhost:5173/missing.png 1280w | ||
| canvas | False | blank canvas after script removal |
先保存真实产品输出,再逐项对照。actualOutput / actualResult 在未执行时保持 not_run,不能把这里的期望值复制成已测结果。