网站设计系统
管理视觉呈现层:移动端图形、暗黑模式和主题令牌。输出/维护 BRAND.md(模板:new-website 技能的 templates/brand.md)以及该技能 templates/astro/src/styles/global.css 中的令牌块。图像规则如下(通过 Astro 的 astro:assets 使用 WebP/AVIF);images.spec.ts 测试强制执行这些规则。如需生成图像资源,请使用 image 技能。
暗黑模式(一等公民)
- 令牌,而非硬编码颜色。 所有颜色通过 CSS 自定义属性流动;亮色是
:root默认值,暗色在:root[data-theme="dark"]下覆盖,此外还有一个@media (prefers-color-scheme: dark)代码块用于无 JavaScript 的访客。启动器已提供这种精确的结构。 - 无 FOUC 脚本 在
<head>中从localStorage.theme或系统偏好设置data-theme(已在Base.astro中配置)。切换开关写入localStorage.theme(启动器未提供;如果添加,请在隐私页面的第 3 节说明)。 - 两种主题均通过对比度测试: 每个文本/背景对都通过 WCAG AA(正文 4.5:1,大/UI 元素 3:1)。在亮色中通过的颜色在暗色中通常失败——可访问性测试在完整的亮色+暗色矩阵中运行,因此请检查两者。
移动端与响应式图形
- 移动端优先: 从 360px 开始设计;触摸目标 ≥ 44px;无水平滚动。在 360 / 768 / 1280 分辨率下验证(使用 preview_resize)。
- 现代格式: 照片使用 WebP(或 AVIF)优于 JPEG/PNG。
- 尺寸与显示匹配,而非源文件。 切勿将 2000px 的图像放入 80px 的空间;生成宽度变体并使用
srcset/sizes(或<picture>)。 - 无布局偏移: 设置显式的
width/height属性,以便在图像加载前预留元素框(保护 CLS / LCP)。Astro 的<Image>会自动设置;images.spec.ts要求这些属性(仅使用 CSS 的 aspect-ratio 无法通过测试)。 - 懒加载与立即加载: 折叠内容以下使用
loading="lazy";LCP/首屏图像使用fetchpriority="high"立即加载(不要对其使用懒加载)。 - 每个图像都有替代文本(仅纯装饰图像使用
alt="")。 - 字体: 自托管 woff2 并设置
font-display: swap;仅预加载首屏使用的 1-2 种字体。避免因后期字体替换导致布局偏移。
文本长度响应式(翻译后的副本)
- 翻译后的文本通常更长。 德语(以及许多其他语言)通常比等效的英文副本长 20-35%。一个适合英文占位符文本的按钮、导航链接或卡片,在真实翻译副本替换后,会悄然溢出、换行混乱或被截断。
- 优先使用弹性宽度。 对包含翻译文本的任何元素使用
min-width/ flex / gridauto/fr尺寸,而不是针对英文字符串设置固定width。 - 溢出 ≠ 宽度: 弹性尺寸无法阻止单个长复合名词(
Datenschutzerklärung)撑破窄列——这需要hyphens: auto(通过Base.astro已设置的lang属性针对每种语言正确配置)以及后备的overflow-wrap: break-word;启动器的global.css在body上同时提供了这两者。表格单元格会关闭连字符(参见表格)。 - 不要仅依赖
white-space: nowrap+text-overflow: ellipsis来处理导航链接或按钮标签——截断导航链接通常不可接受(访客将无法知道其目的地)。对于内容截断是可接受权衡的场景(例如表格单元格)可以接受,但不适用于导航。 - 使用真实的翻译标签进行验证,而非英文占位符。 当网站部署了
astro-i18n-setup的LanguageSwitcher.astro或任何双语/多语言导航时,请使用每种语言实际发布的副本检查 360/768/1280 分辨率下的布局——而不仅仅是英文占位符。
表格
所有表格共用一种样式;页面中不应包含任何表格的布局 CSS。它位于启动器的 src/styles/tables.css 中(由 Base.astro 在 global.css 之后导入),并由 tests/tables.spec.ts 检查。在此部分之前创建的网站需要复制 tables.css 文件,将其导入行添加到布局中,并首先移除每个页面自己的表格 CSS。
两种类型,根据单元格内容区分:
stack(句子):在屏幕宽度超过 40rem 时显示为表格;低于该宽度时,每行堆叠,行标题作为标题,每个单元格显示在其列名下方。四列散文无法共享 320px 空间。figures(短数字,数字单元格添加class="num"):在手机上保持表格布局,必须适应 320px 宽度。如果不再适应,将其改为stack;滚动条不是解决方案。stack figures一起使用可实现堆叠布局下的数据显示样式。
标记,每个表格:
<div class="table-wrap stack" role="region" aria-label="表格内容说明" tabindex="0">
<table role="table">
<thead role="rowgroup"><tr role="row">
<th scope="col" role="columnheader">{cols[0]}</th><th scope="col" role="columnheader">{cols[1]}</th>
</tr></thead>
<tbody role="rowgroup">{rows.map((r) => (
<tr role="row"><th scope="row" role="rowheader">{r.item}</th><td role="cell" data-label={cols[1]}>{r.text}</td></tr>
))}</tbody>
</table>
</div>
- 将列名写在一个列表中,同时用于表头和每个
data-label:堆叠单元格的标签必须等于其列表头,测试会比较两者。figures表格不需要每个单元格的角色和data-label。 - 堆叠表格不再是
display: table。这些角色是当布局改变时浏览器丢弃表格情况下的后备方案;其有效性未经验证。在 Chromium 中,在真实表格上测量一次,可访问性树在没有角色时仍保留表格。 class="tap"应用于单元格中独立的链接,使其在手机上成为 44px 的触摸目标。nowrap可将短值(1, 3, 6)保持在一行。long-head(与stack一起使用)在行标题为句子时加宽第一列。- 单元格中的单词不会连字符化。正文的
hyphens: auto会将窄的第一列压缩成碎片(“An-thropic”),因此代码块在此处设置hyphens: manual。 - 来自外部且无法承载此标记的表格页面应放入规范中的
TABLE_EXEMPT,并说明原因。PAGES保持完整:站点地图和llms.txt检查需要其中的每个活跃路由。
tables.spec.ts 检查的内容:每个表格都是一个 .table-wrap 的其中一种类型,具有其区域、标签和 tabindex,每个表头单元格有 scope="col",每行第一个单元格为 <th scope="row">,其余为 <td>;堆叠表格具有角色,并且每个单元格的标签等于表头;在 360 和 320px 下,没有页面或表格水平滚动;在 641px 及以上,堆叠表格再次显示为表格,显示表头行且单词未被断开(这捕获了诸如 overflow-wrap: anywhere 之类的规则,该规则允许列挤压单词);没有单元格使用 hyphens: auto。它还测试添加到主页面的固定 CSS,并在两种主题下使用 axe 进行测试,因此即使没有表格的网站也能证明代码块的有效性。无头 Chromium 不会连字符化,因此连字符保护读取计算后的样式,而非布局。Safari 和 VoiceOver 未检查。
电子邮件混淆(隐藏地址以防爬虫)
切勿在 HTML 源代码中放置纯文本电子邮件地址或 mailto:your@addr——爬虫会立即抓取这些地址用于发送垃圾邮件。通过 EmailLink.astro 组件(new-website 技能 templates/astro/ 目录下的 src/components/EmailLink.astro,加上其 lib/obfuscate.ts 辅助程序)渲染每个地址:地址在构建时被反转并 base64 编码,在浏览器中重新组装,因此提供的 HTML 不包含可读的地址。无 JavaScript 的访客会看到一个仍然可用的“name [at] domain [dot] com”提示。
<EmailLink address="[email protected]" subject="项目咨询" text="给我们发邮件" />
规则:构建后的 HTML 中零个原始 mailto: 链接和零个文字 @-地址——website-qa 会检查此项。任何不希望被抓取的电话号码也采用相同的方式。
品牌令牌
将 BRAND.md 的调色板镜像到令牌块中并保持同步。定义:品牌色(固定),以及每个主题的标题色/墨色/弱化色/强调色/链接色/线条色/背景色/背景柔和色/表面色。强调色和链接色必须在两种主题下均能通过背景的 AA 对比度测试,这就是为什么每个主题都有自己颜色的原因。可选的 website-brand-kit 通过检查执行镜像操作:其读取操作读取 BRAND.md 的表格,在两种主题下将所有文本颜色与每个背景的 4.5:1 对比度进行比较,并将这些值写入 global.css 的所有三个颜色块(亮色、暗色以及面向无 JavaScript 访客的暗色块)。手动操作时,请一起更改所有三个块。
完成的定义
BRAND.md 已填写并与令牌块一致;图像为 WebP 格式、尺寸正确、懒加载/立即加载正确、具有替代文本;可访问性测试(亮色+暗色)通过;布局在 360/768/1280 下保持不变且无偏移;每个表格为 stack 或 figures 且 tables.spec.ts 通过。性能指标(FCP/LCP)已在 website-qa 中验证。布局在 360/768/1280 下使用每种发布语言的真实(而非占位符)副本进行验证,而不仅仅是默认区域设置。