政府与公共服务 · 新资源

ONS 设计系统.

构建一个前后不会矛盾的调查问卷:使用 ONS 原生复选框、互斥选项、准确的字体和颜色引用,以及完整的本地回顾流程。

OpenDesign 指南8 个章节26 条参考条目原始应用指南
01

ONS 设计系统 界面预览

试试不同的出行方式、与之矛盾的答案、空值校验、本地预览和保留已编辑内容。

无法自相矛盾的问卷答案打开完整示例
原生 ONS 73.13.1 Checkbox 和互斥的 CSS/JavaScript。原创问题、应用校验与预览,并明确回退到 Arial。· 实现参考
02

ONS 设计系统 设计参考

ONS Design System 73.13.1 已编译 CSS、JavaScript 和 Sass 变量,并对照公开服务手册进行了检查。示例使用原生 Checkbox 和 Mutually Exclusive 行为。独立示例使用 Arial 替代 OpenSans;生产环境的复制配置包含打包字体。旅行问题和本地预览内容均为原创演示内容。

字号矩阵

来源
名称 / 规则值 / 配置用途
Primary familyOpenSans, Helvetica Neue, Arial, sans-serif官方字体指南指定使用 Open Sans 的 stylistic set 1;演示特意使用 Arial。
ons-u-fs-3xl32/44px → 48/56px在 medium 断点从小号变为大号;字重 700。
ons-u-fs-2xl28/40px → 36/48px字重 700;层级与标题字号相当。
ons-u-fs-xl / ons-u-fs-l26/36 → 30/40px; 24/32 → 26/36px采用原生响应式字号和行距,不使用流体 clamp。
ons-u-fs-m20/28px → 22/32px字重 700。
ons-u-fs-r / ons-u-fs-s18/28px / 14/20px常规字重 400;--b 变体使用 700。

语义化颜色角色

来源
名称 / 规则值 / 配置用途
--ons-color-text#222映射到 --ons-color-black。
--ons-color-text-link#206095 海洋蓝;悬停/激活状态使用夜蓝 #003c57。
--ons-color-focus#fbc900 向日葵黄焦点提示。
--ons-color-button#0f8243 叶绿;与链接颜色区分。
--ons-color-errors#d0021b 宝石红用于错误,并配有文字说明。
--ons-color-info-tint#e9eff4 信息面板背景;不能替代已选中的复选框样式。

实际间距工具类

来源
名称 / 规则值 / 配置用途
ons-u-mb-xs / s / m12px /16px /20px根字号为 16px 时的底部边距工具类数值。其中包含超出文档所述 8px 网格基准的间距级别。
ons-u-mb-l / xl24px /32px使用已发布版本中的工具类;不要仅依据基准说明推断所有数值。

布局与响应式模型

来源
名称 / 规则值 / 配置用途
Grid12 percentage-width columnsons-grid > ons-grid__col,搭配响应式列类。
Medium columnons-col-8@m从 740px 起占八列;低于该宽度时占满整行。
Breakpoints300,400,500,740,980,1300,1600px2xs、xs、s、m、l、xl、2xl。
BaselineMultiples of8px网格文档中的间距节奏;不要假定所有边框/字体都遵循这一节奏。
Documented gutters16px below600;24px at600+如需覆盖网格类,请检查版本 CSS。
Default container64.6256rem maximum;1rem horizontal padding已验证 73.13.1 CSS,根字号为 16px 时宽度约为 1034px。

互斥选项钩子

来源
名称 / 规则值 / 配置用途
Group rootons-js-mutually-exclusive原生脚本会在 DOM 就绪时查找此容器。
Regular optionsons-js-exclusive-group-item可以组合使用;选择一个选项会清除与之互斥的选项。
Opposing choiceons-js-exclusive-option选择此选项会清除普通选项组中的选项。
Explanationdata-deselect-message针对互斥选项的警告文本。
Announcementons-js-exclusive-alert包含 data-group-adjective 和 data-option-adjective 的实时区域。
State updatesclick for checkbox/radio;input for text控制器会缓存 hasValue;应用重置时应使用原生事件。
03

ONS 设计系统 完整指南

实用指南,介绍如何为真实界面选择、应用和评审此系统。

DESIGN-ons.md

完整指导、实现起点和源代码链接。

下载指南

ONS 设计系统 问卷专属设计

确保答案含义清晰

ONS 除发布信息外,也负责统计数据收集。对于问卷而言,互斥选项关系到数据质量:用户不能同时提交一种出行方式,以及表示没有出行的答案。原生 Mutually Exclusive 组件会关联这些选项,并向辅助技术说明取消选择的原因。

摘自本 OpenDesign 指南

本示例提出原创的图书馆出行问题,并提供本地答案预览。它刻意避免使用 ONS 标识图形,也不会声称答案已被收集。生产问卷还需要自行处理用户同意、数据保留、路由和服务器端验证。

阅读配套规范

ONS 设计系统 清晰易读的问题层级

可以将图例用作页面标题

主要字体为 Open Sans,并选用 stylistic set 1,以呈现独特的字形。原生 Sass 字号矩阵采用固定的小号和大号字号,而非自行设计连续字号比例。正文字号保持为 18px,行距为 28px。主要大号样式会在 medium 断点从 32/44 调整为 48/56。

对于只有一个问题的页面,可以将 h1 放在 fieldset 的 legend 内,使问题组的无障碍名称与可见标题保持一致。不要在它上方另设一个无关的 h1。示例将服务背景说明作为较小的段落,并将选项说明放在 legend 下方。

独立演示明确使用 Arial,因此不会请求缺失的字体。安装配置会将字体与 CSS 一并复制;如果使用方希望使用已发布的 OpenSans 字体而非备用字体,就需要这样做。

阅读配套规范

ONS 设计系统 问卷界面中的角色

焦点状态与状态含义相互独立

ONS 为基础色指定语义变量。文本使用黑色,普通链接使用海洋蓝,主按钮使用叶绿。向日葵黄用于焦点状态。宝石红表示错误,但错误消息仍须说明需要采取什么操作。绿色的“继续”按钮并不表示答案已通过验证。

本地问卷使用原生复选框边框和选中样式。它不会把每个答案都设计成独立的营销卡片。简洁、中性的顶部横线将独立示例与问题分隔开,同时避免仿制 ONS 页眉。

  • 保留复选框输入框和操作按钮上原生可见的焦点样式。
  • 在普通选项前使用“可多选”这一文字说明。
  • 在互斥答案前使用“或者”进行分隔,让用户在操作前就能看出它与其他选项的区别。

阅读配套规范

ONS 设计系统 栏数与答案宽度

采用问卷内容宽度

十二栏网格通过 ons-col-8@m 等类来定义宽度。从 740px 起,该类占八栏;低于此宽度时,同一元素会占满可用内容宽度。本地示例使用这一原生列类,使较长的问题能够以易读的宽度换行,而不会在桌面端横向铺满整个页面。

在检查的版本中,标准容器的最大宽度为 64.6256rem,水平内边距为 1rem。公开网格指南还说明了 8px 基准,以及围绕 600px 间距边界设置的 16/24px 间隔。请将这些概念与 740px 的 medium 栏断点区分开来;它们并不是一个适用于所有情况的移动端切换点。

答案预览会在同一栏内替换问题内容,“更改答案”则会返回现有选项。答案值会保留在内存中,不会更改路由或发出网络请求。

实际可用的间距工具类比 8px 基准说明更细:根字号为 16px 时,xs、s、m、l 和 xl 的底部边距分别为 12、16、20、24 和 32px。因此,参考资料将实际工具类数值与网格指南分开列出。

阅读配套规范

ONS 设计系统 构建答案选项组

原生复选框结构

复选框使用 ons-checkbox__input 和关联的 ons-checkbox__label,并置于 ons-checkbox 内。输入框保留普通的 name 和 value 属性,因此仍可使用原生表单语义。更外层的 ons-checkboxes__item 结构提供样式表所要求的间距和可点击区域。

常规选项使用 ons-js-exclusive-group-item。最后一个选项则使用 ons-js-exclusive-option,并通过 data-deselect-message 说明其效果。带有这两个修饰属性的实时区域 span 必须存在,并非可有可无的装饰性标记。移除它会破坏原生控制器的预期。

此示例包含三个常规选项和一个相反选项,结构完整。请根据实际问题调整名词和选项值;不要只把无关的验证控件改名为“互斥”控件。

html
<fieldset class="ons-fieldset"><legend class="ons-fieldset__legend"><h1 class="ons-fieldset__legend-title">How did you travel to your local library last week?</h1></legend>
<div class="ons-js-mutually-exclusive ons-mutually-exclusive">
<p class="ons-checkboxes__label">Select all that apply</p><div class="ons-checkboxes__items"><span class="ons-checkboxes__item"><span class="ons-checkbox"><input type="checkbox" id="walk" name="travel" value="walk" class="ons-checkbox__input ons-js-checkbox ons-js-exclusive-group-item"><label class="ons-checkbox__label" for="walk" id="walk-label">Walk or wheel</label></span></span><br><span class="ons-checkboxes__item"><span class="ons-checkbox"><input type="checkbox" id="cycle" name="travel" value="cycle" class="ons-checkbox__input ons-js-checkbox ons-js-exclusive-group-item"><label class="ons-checkbox__label" for="cycle" id="cycle-label">Cycle</label></span></span><br><span class="ons-checkboxes__item"><span class="ons-checkbox"><input type="checkbox" id="bus" name="travel" value="bus" class="ons-checkbox__input ons-js-checkbox ons-js-exclusive-group-item"><label class="ons-checkbox__label" for="bus" id="bus-label">Bus or tram</label></span></span><br></div>
<p class="ons-checkboxes--mutually-exclusive__item ons-u-mt-s"><span class="ons-checkboxes__label ons-u-fs-r--b" aria-hidden="true">Or</span><span class="ons-checkbox"><input type="checkbox" id="none" name="travel" value="none" class="ons-checkbox__input ons-js-checkbox ons-js-exclusive-option" data-deselect-message="Selecting this will uncheck all other options"><label class="ons-checkbox__label" for="none" id="none-label"><span class="ons-u-vh">Or, </span>I did not visit the library</label></span></p>
<span class="ons-js-exclusive-alert ons-u-vh" role="alert" aria-live="polite" data-group-adjective="deselected" data-option-adjective="deselected"></span></div></fieldset>

代码参考

阅读配套规范

ONS 设计系统 验证与更改行为

库状态与应用状态

由库负责清除相反选项。示例中的简短应用处理程序只会检查是否至少有一个答案,然后显示本地答题回顾。如果未选择任何选项,它会显示文字错误信息,并将焦点移至关联的消息。错误链接会直接指向第一个选项,方便用户进行操作。

除了 DOM 复选框的值,控制器还会跟踪缓存的 hasValue 状态。仅使用 checked=false 重置,可能导致缓存过期。因此,重置操作会逐一点击已选中的输入框,让原生监听器更新其模型,然后将焦点移回问题。这是具体的集成问题,无法仅通过查看样式表来检查。

答题回顾会以列表形式显示已选标签。“更改答案”会保留控件及其选择状态。由于此示例没有连接服务器,因此不会显示任何声称已收到调查回复的成功面板。

阅读配套规范

ONS 设计系统 资源与模板接入

两种受支持的接入方式

npm 包包含编译后的资源、Sass 源文件、Nunjucks 宏和基础页面模板。本预览采用编译后的 HTML 接入方式:复制官方的 CSS 和 main.js,按文档重现标记,然后在正文内容之后加载脚本。DOM 就绪后,脚本会初始化匹配的组件钩子。

服务器端渲染项目也可以使用 components 中的 Nunjucks 宏文件。Checkbox 宏接受复选框数组、标签、说明、错误配置和 mutuallyExclusive 配置。设置 dontWrap 后,外层问题组件将负责 fieldset;这并不意味着可以省略无障碍组名称。

如果选择单独的 Sass 文件,请先导入系统变量、辅助项、工具类、基础样式和对象,再导入组件规则及其依赖项。对于这个小型独立示例,使用完整编译后的 CSS 可免去选择依赖项的步骤。

  1. 固定软件包版本,并将 css、scripts 和 fonts 放在同一个稳定的本地资源目录下提供。
  2. 静态页面请选择编译后的 HTML;服务器端渲染应用则配置 Nunjucks 宏路径。
  3. 确保 CSS、JavaScript 和标记来自同一版本;升级后重新检查互斥行为。

阅读配套规范

ONS 设计系统 测试相互矛盾的答案

核验数据含义

选择 Walk 和 Bus,再选择“I did not visit.”前两个选项都应取消选中。然后选择 Cycle:相反选项应取消选中,而 Cycle 保持选中。接着在聚焦的输入框上按空格键重复操作,并检查公告区域,不要以为视觉上的勾选标记就能证明所有行为正常。

保持未选择状态并继续操作,以测试错误提示;然后提交有效答案并查看回顾,再通过“更改答案”返回。最后,在一组相互矛盾的答案操作后重置并重新选择,以发现原生控制器状态是否过期。在 390px 宽度下,问题和所有标签都应清晰可读,页面无需横向滚动。

这些测试验证的是本地交互,不代表生产环境中的调查数据提交、无障碍认证或问题设计质量。真实服务仍需在服务器端验证相互矛盾的值,并研究回复选项是否完整。

阅读配套规范

ONS 设计系统组件示例

完整的互斥问题

常规答案选项和带有原生实时区域钩子的相反选项。

html
<fieldset class="ons-fieldset"><legend class="ons-fieldset__legend"><h1 class="ons-fieldset__legend-title">How did you travel to your local library last week?</h1></legend>
<div class="ons-js-mutually-exclusive ons-mutually-exclusive">
<p class="ons-checkboxes__label">Select all that apply</p><div class="ons-checkboxes__items"><span class="ons-checkboxes__item"><span class="ons-checkbox"><input type="checkbox" id="walk" name="travel" value="walk" class="ons-checkbox__input ons-js-checkbox ons-js-exclusive-group-item"><label class="ons-checkbox__label" for="walk" id="walk-label">Walk or wheel</label></span></span><br><span class="ons-checkboxes__item"><span class="ons-checkbox"><input type="checkbox" id="cycle" name="travel" value="cycle" class="ons-checkbox__input ons-js-checkbox ons-js-exclusive-group-item"><label class="ons-checkbox__label" for="cycle" id="cycle-label">Cycle</label></span></span><br><span class="ons-checkboxes__item"><span class="ons-checkbox"><input type="checkbox" id="bus" name="travel" value="bus" class="ons-checkbox__input ons-js-checkbox ons-js-exclusive-group-item"><label class="ons-checkbox__label" for="bus" id="bus-label">Bus or tram</label></span></span><br></div>
<p class="ons-checkboxes--mutually-exclusive__item ons-u-mt-s"><span class="ons-checkboxes__label ons-u-fs-r--b" aria-hidden="true">Or</span><span class="ons-checkbox"><input type="checkbox" id="none" name="travel" value="none" class="ons-checkbox__input ons-js-checkbox ons-js-exclusive-option" data-deselect-message="Selecting this will uncheck all other options"><label class="ons-checkbox__label" for="none" id="none-label"><span class="ons-u-vh">Or, </span>I did not visit the library</label></span></p>
<span class="ons-js-exclusive-alert ons-u-vh" role="alert" aria-live="polite" data-group-adjective="deselected" data-option-adjective="deselected"></span></div></fieldset>

代码参考

使用同一版本的资源

编译资源接入方式,包含完整项目所需的相对字体资源。

bash / html
npm install --save-exact @ons/[email protected]
mkdir -p public/vendor/ons
cp -R node_modules/@ons/design-system/css public/vendor/ons/
cp -R node_modules/@ons/design-system/scripts public/vendor/ons/
cp -R node_modules/@ons/design-system/fonts public/vendor/ons/

<!-- In your page head -->
<link rel="stylesheet" href="/vendor/ons/css/main.css">
<!-- Place the compiled component markup in the body. -->
<!-- Immediately before </body>; initializes matching component hooks -->
<script src="/vendor/ons/scripts/main.js"></script>

代码参考

完整的独立示例

完整文档包含其布局、控件与初始化。解压所链接的示例归档,即可获得完全一致的相对 vendor 资源,然后通过 HTTP 提供服务。

html
<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>ONS survey question specimen</title><link rel="stylesheet" href="vendor/ons-73.13.1/css/main.css"><style>body,input,button,select,textarea{font-family:Arial,sans-serif!important}body{margin:0}main{padding-top:32px;padding-bottom:32px}.specimen{border-top:4px solid var(--ons-color-ocean-blue);padding-top:16px}.actions{display:flex;gap:24px;align-items:center;flex-wrap:wrap;margin-top:32px}[hidden]{display:none!important}.error{border-left:4px solid var(--ons-color-errors);padding:16px;margin:24px 0;color:var(--ons-color-errors)}.quiet{color:var(--ons-color-text-light)}fieldset{min-width:0}.ons-checkbox__label{max-width:100%}</style><main class="ons-container"><p class="ons-u-fs-s specimen">Independent specimen · Original library survey</p><div class="ons-grid"><div class="ons-grid__col ons-col-8@m"><section id="question"><p class="quiet">Travel · Question 1 of 1</p><div id="error" class="error" tabindex="-1" hidden><strong>Select a travel method or tell us you did not visit.</strong><p><a href="#walk">Go to the answer choices</a></p></div><form id="survey" novalidate><fieldset class="ons-fieldset"><legend class="ons-fieldset__legend"><h1 class="ons-fieldset__legend-title">How did you travel to your local library last week?</h1></legend>
<div class="ons-js-mutually-exclusive ons-mutually-exclusive">
<p class="ons-checkboxes__label">Select all that apply</p><div class="ons-checkboxes__items"><span class="ons-checkboxes__item"><span class="ons-checkbox"><input type="checkbox" id="walk" name="travel" value="walk" class="ons-checkbox__input ons-js-checkbox ons-js-exclusive-group-item"><label class="ons-checkbox__label" for="walk" id="walk-label">Walk or wheel</label></span></span><br><span class="ons-checkboxes__item"><span class="ons-checkbox"><input type="checkbox" id="cycle" name="travel" value="cycle" class="ons-checkbox__input ons-js-checkbox ons-js-exclusive-group-item"><label class="ons-checkbox__label" for="cycle" id="cycle-label">Cycle</label></span></span><br><span class="ons-checkboxes__item"><span class="ons-checkbox"><input type="checkbox" id="bus" name="travel" value="bus" class="ons-checkbox__input ons-js-checkbox ons-js-exclusive-group-item"><label class="ons-checkbox__label" for="bus" id="bus-label">Bus or tram</label></span></span><br></div>
<p class="ons-checkboxes--mutually-exclusive__item ons-u-mt-s"><span class="ons-checkboxes__label ons-u-fs-r--b" aria-hidden="true">Or</span><span class="ons-checkbox"><input type="checkbox" id="none" name="travel" value="none" class="ons-checkbox__input ons-js-checkbox ons-js-exclusive-option" data-deselect-message="Selecting this will uncheck all other options"><label class="ons-checkbox__label" for="none" id="none-label"><span class="ons-u-vh">Or, </span>I did not visit the library</label></span></p>
<span class="ons-js-exclusive-alert ons-u-vh" role="alert" aria-live="polite" data-group-adjective="deselected" data-option-adjective="deselected"></span></div></fieldset><div class="actions"><button class="ons-btn" type="submit"><span class="ons-btn__inner">Review answer</span></button><button id="reset" type="button" class="ons-btn ons-btn--secondary"><span class="ons-btn__inner">Reset</span></button></div></form><p class="ons-u-mt-l ons-u-fs-s quiet">Practice only. Your selection stays in this page and is not submitted.</p></section><section id="review" hidden><h1 tabindex="-1">Review your answer</h1><h2 class="ons-u-fs-m">Travel to the library last week</h2><ul id="answer"></ul><p>No response has been sent. Return to the question to change your selection.</p><button id="change" class="ons-btn ons-btn--secondary"><span class="ons-btn__inner">Change answers</span></button></section></div></div></main><script src="vendor/ons-73.13.1/scripts/main.js"></script><script>const form=document.querySelector('#survey'),q=document.querySelector('#question'),r=document.querySelector('#review'),err=document.querySelector('#error'),checks=[...form.querySelectorAll('input[type=checkbox]')];form.onsubmit=e=>{e.preventDefault();const chosen=checks.filter(x=>x.checked);if(!chosen.length){err.hidden=false;err.focus();return}err.hidden=true;document.querySelector('#answer').replaceChildren(...chosen.map(x=>{let li=document.createElement('li');li.textContent=document.querySelector('label[for="'+x.id+'"]').textContent.replace(/^Or, /,'');return li}));q.hidden=true;r.hidden=false;r.querySelector('h1').focus()};document.querySelector('#change').onclick=()=>{r.hidden=true;q.hidden=false;checks[0].focus()};document.querySelector('#reset').onclick=()=>{checks.filter(x=>x.checked).forEach(x=>x.click());err.hidden=true;checks[0].focus()};window.demoReady=true;</script></html>

代码参考

  • 从“来源”一节下载完整示例。其 README 给出了确切的本地启动命令。
  • 保持 vendor 路径相对于本文档;该归档包含此预览所使用的全部资源。
04

ONS 设计系统 Agent 设置

实现起点

本地示例运行的是原生 73.13.1 编译后的 CSS 和 JavaScript。Arial 是明确指定的本地后备字体;生产环境的复制说明中包含打包好的 OpenSans 字体。Sources 中的完整可运行示例 ZIP 还提供了准确的预览依赖项和完整文档。解压后,在该目录运行 python3 -m http.server 8080,然后打开 http://localhost:8080/ons.html。请勿通过 file:// 打开基于模块的示例。

bash / html
npm install --save-exact @ons/[email protected]
mkdir -p public/vendor/ons
cp -R node_modules/@ons/design-system/css public/vendor/ons/
cp -R node_modules/@ons/design-system/scripts public/vendor/ons/
cp -R node_modules/@ons/design-system/fonts public/vendor/ons/

<!-- In your page head -->
<link rel="stylesheet" href="/vendor/ons/css/main.css">
<!-- Place the compiled component markup in the body. -->
<!-- Immediately before </body>; initializes matching component hooks -->
<script src="/vendor/ons/scripts/main.js"></script>

适用于你项目的提示词

Agent 提示词
构建一个独立的 ONS73.13.1 调查示例,使用原生 Checkbox 和 Mutually Exclusive 钩子、关联的 fieldset/legend、常规答案组和一个相反选项。包含必需的实时区域和取消选择属性。提供匹配版本的原生 CSS 和 main.js;不要编写替代的互斥控制器。添加本地的未填写验证和答案回顾,并在保留编辑内容的情况下返回;不要声称服务器已收到答案。通过原生事件重置,以保持缓存状态一致。使用 ons-col-8@m,以及经过核验的字体和语义配色规则,不要使用官方身份标识。
05

ONS 设计系统 来源与范围

采用原创调查措辞的独立实现示例。原生代码采用 MIT 许可证;ONS 身份标识和内容的许可另行规定。不会传输或保存任何答案,也不会将其作为官方统计数据展示。