政府与公共服务 · 新资源

Aksel 设计系统.

使用 Aksel v8 的真实 ax 令牌、原生表格密度和语义化表头结构。对虚构的后续记录进行排序和选择,并比较浅色与深色主题。

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

Aksel 设计系统界面预览

对等待天数进行数值排序、选择记录、切换密度,并对比浅色和深色主题角色。

跟进表格工作台打开完整示例
使用原生 Aksel 8.18.0 表格 CSS 和令牌,以及语义化 HTML;本地排序和选择代码,并显式回退到 Arial。· 实现参考
02

Aksel 设计系统设计参考

检查了 @navikt/ds-css 8.18.0 的原生样式表和当前 v8 文档。浅色和深色值均有作用域限制;预览将远程字体替换为 Arial,并使用原始示例记录。

v8 字体排印

来源
名称 / 规则值 / 配置用途
--ax-font-familySource Sans 3, Source Sans Pro, Arial, sans-serif预览明确使用 Arial 作为备用字体。
--ax-font-weight-regular / bold400 / 600不要将名为 bold 的令牌等同于 700。
--ax-font-size-medium / large1rem / 1.125rem标准根字号下为 16px / 18px。
--ax-font-size-heading-xlarge / 2xlarge2rem / 2.5rem32px / 40px。

间距与断点

来源
名称 / 规则值 / 配置用途
--ax-space-8 / 16 / 24 / 320.5 / 1 / 1.5 / 2rem令牌名称描述的是标准像素等效值。
--ax-radius-2 / 4 / 8 / 12 / 162 / 4 / 8 / 12 / 16px圆角角色。
sm / md / lg / xl / 2xl480 / 768 / 1024 / 1280 / 1440px在有版本号的 CSS 中检查的值。

原生表格几何尺寸

来源
名称 / 规则值 / 配置用途
Medium cell padding12px 8px默认垂直 / 水平内边距。
Small / large vertical padding4px / 16px原生密度修饰符;水平内边距保持为 8px。
Header divider2px正文行分隔线保持为 1px。

主题角色

来源
名称 / 规则值 / 配置用途
--ax-bg-default#fff light / #0e151f dark根级界面表面。
--ax-text-neutral#202733 light / #dfe1e5 dark解析后的 neutral-1000 值。
--ax-bg-accent-strong#2176d4 light / #4580ca dark解析后的 accent-600 值;代码中应使用角色名称。
03

Aksel 设计系统完整指南

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

DESIGN-nav-aksel.md

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

下载指南

Aksel 设计系统:从 v8 契约入手

不要混用旧类名和新令牌

Aksel v8 使用 --ax-* 令牌和 .aksel 组件类。迁移指南指出,旧的 .navds 类已不再有效,组件专属令牌也已移除。因此,基于旧版截图制作的教程看起来可能合情合理,实际上却会给出无法正常使用的实现建议。

摘自本 OpenDesign 指南

此页面将原生 CSS 固定为 8.18.0,并提供对应的 React 安装方式。预览使用检查过的原生表格类和常规 HTML;选中和排序由应用程序 JavaScript 负责。这里并未声称下载样式表就能实例化 React Table。

阅读配套规范

Aksel 设计系统:类型角色与字体加载

粗体令牌使用 600

令牌参考中定义的字体栈为 Source Sans 3、Source Sans Pro、Arial 和 sans-serif。常规字重为 400,命名的粗体令牌为 600。正文字号包括 14、16、18 和 20px;标题角色的字号还包括 24、28、32 和 40px。

本地预览将字体令牌设为 Arial,并明确覆盖继承的字体设置,因此不会请求远程字体。这是已说明的回退选择,并不表示 Arial 是 Aksel 的主要字体。组件文本字号仍由 CSS 提供。

阅读配套规范

Aksel 设计系统:间距、圆角与布局

以像素命名的令牌会解析为 rem

--ax-space-16 为 1rem,--ax-space-24 为 1.5rem。v8 的基础组件语法遵循这些名称:padding="space-16" 和 gap={{xs:"space-8",md:"space-16"}}。未经查阅迁移指南,不要直接替换为旧版数字间距属性。

文档中列出的圆角角色包括 2、4、8、12 和 16px,以及 full。预览保留原生表格的几何样式,并在应用程序控件周围使用 space-24。64rem 的阅读宽度是本地选择;断点值则来自检查过的样式表。

阅读配套规范

Aksel 设计系统:适配主题的语义色彩

保留颜色角色,而非固定的十六进制值

原生样式表会将 --ax-text-neutral 解析为 neutral-1000:浅色模式下为 #202733,深色模式下为 #dfe1e5。--ax-bg-default 则会从白色切换为 #0e151f。在深色容器中硬编码浅色文本值,会破坏角色映射。

预览会切换 .light/.dark 主题类,并让表格的条纹、边框和选中行颜色遵循官方令牌。选中状态仍会显示已勾选的复选框和明确的数量。仅用颜色标记行,并不能构成选中界面。

阅读配套规范

Aksel 设计系统:语义化表格结构

表头不是普通单元格

原生表格使用不同的表头、表体、行、表头单元格和数据单元格类。React 中对应的组件是 Table.Header、Table.Body、Table.Row、Table.HeaderCell 和 Table.DataCell。参考编号列是行标题,每个列标题都设置了 scope=col。

使用标题说明表格所呈现的集合。等待天数属于数值,应右对齐;参考编号应保持左对齐。在窄屏下,预览将横向滚动限制在一个带有标签且可通过键盘聚焦的区域内,而不是把表格改造成卡片行、破坏表格关系。

  • 列标签和行标识都应使用标题单元格。
  • 数值应右对齐;邮政编码和标识符则不应右对齐。
  • 提供标题,让表格拥有有意义的名称。

阅读配套规范

Aksel 设计系统:密度与排序

更改密度会改变内边距

在检查过的原生 CSS 中,中等密度单元格的垂直间距为 space-12,水平间距为 space-8;小密度的垂直间距为 space-4,大密度的垂直间距为 space-16。密度选择器会更改原生修饰类,而不是缩小正文以强行在视口中塞入更多信息。

“等待天数”表头是一个原生风格的排序按钮。其处理程序会按数值排序,并更新该表头上的 aria-sort。此转换由应用程序负责:React API 同样会提供排序状态和 onSortChange,而不会自动对任意领域记录排序。

阅读配套规范

Aksel 设计系统:适用于键盘操作的行选择

为每一行提供明确的操作控件

Table 文档指出,仅使用 onRowClick 无法通过键盘访问。因此,示例为每个参考编号提供带标签的复选框,并提供全选复选框。仅选中部分行时,汇总复选框会进入不确定状态。

排序时,通过稳定的参考编号保留选中状态。绝不使用当前行索引作为选中键,因为顺序变化时,勾选状态会转移到其他记录。选中数量会在礼貌提示状态区域中更新。不会向任何地方发送所选记录。

阅读配套规范

Aksel 设计系统:加载匹配的 CSS 和 React

保持软件包版本一致

以相同版本安装 @navikt/ds-react 和 @navikt/ds-css,然后在应用程序根部附近导入一次 CSS。软件包已包含令牌。官方 CSS 导入指南也支持按需导入全局文件和组件文件,但必须包含基础样式,并且必须提供字体和令牌,或明确替换它们。

Aksel 使用 CSS 层。避免使用宽泛、未分层的选择器,以免意外覆盖组件样式。自定义应用布局应使用自己的类。独立预览使用本地固定版本的 CSS,并有意替换了字体;React 示例则是另一条经源代码验证的集成路径。

  1. 将 React 和 CSS 软件包版本一并固定。
  2. 只导入一次样式表,并渲染语义化的 Table 子组件。
  3. 在应用程序状态中管理排序和选择。
  4. 检查主题切换、键盘控件和窄屏滚动区域。

阅读配套规范

Aksel 设计系统:组件示例

语义化的 React Table

使用真正的 Table 子组件和行标题;数值右对齐。

jsx
import { Table } from '@navikt/ds-react';
import '@navikt/ds-css';

export function CaseTable() {
  return <Table size="medium" zebraStripes>
    <caption>Fictional follow-up records</caption>
    <Table.Header><Table.Row>
      <Table.HeaderCell scope="col">Reference</Table.HeaderCell>
      <Table.HeaderCell scope="col">Next activity</Table.HeaderCell>
      <Table.HeaderCell scope="col" align="right">Waiting days</Table.HeaderCell>
    </Table.Row></Table.Header>
    <Table.Body><Table.Row>
      <Table.HeaderCell scope="row">DEMO-204</Table.HeaderCell>
      <Table.DataCell>Confirm appointment preference</Table.DataCell>
      <Table.DataCell align="right">4</Table.DataCell>
    </Table.Row></Table.Body>
  </Table>;
}

代码参考

当前的响应式基础组件语法

在基础组件属性中使用 v8 令牌名称。

jsx
import { HStack, Box } from '@navikt/ds-react';
<HStack gap={{ xs: 'space-8', md: 'space-16' }}>
  <Box padding="space-16">First region</Box>
  <Box padding="space-16">Second region</Box>
</HStack>

代码参考

完整的独立示例

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

html
<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Aksel table workbench</title><link rel="stylesheet" href="vendor/aksel-8.18.0/index.css"><style>:root{--ax-font-family:Arial,sans-serif}body,body *,body *:before,body *:after{font-family:Arial,sans-serif!important}body{background:var(--ax-bg-default);color:var(--ax-text-neutral);font-size:18px;line-height:1.5}main{max-width:64rem;padding:32px 24px;margin:auto}h1{font-size:32px;font-weight:600;line-height:1.25;margin:16px 0 24px}p{margin:16px 0}.toolbar{display:flex;gap:24px;flex-wrap:wrap;padding:24px;background:var(--ax-bg-sunken);margin:24px 0}select{font-size:16px;padding:8px;background:var(--ax-bg-input);color:var(--ax-text-neutral);border:1px solid var(--ax-border-neutral)}label{font-size:16px;display:flex;gap:8px;align-items:center}.scroll{overflow-x:auto}table{min-width:38rem}caption{text-align:left;font-weight:600;margin-bottom:16px}input[type=checkbox]{width:20px;height:20px;accent-color:var(--ax-bg-accent-strong);cursor:pointer}small{font-size:14px;display:block;margin-top:24px;color:var(--ax-text-neutral-subtle)}:focus-visible{outline:3px solid var(--ax-border-focus);outline-offset:3px}@media(max-width:767px){main{padding:24px 16px}.toolbar{padding:16px;gap:16px}h1{font-size:28px}}</style><body class="light"><main><p>AKSEL v8 · NATIVE TABLE CSS</p><h1>Follow-up record workbench</h1><p>Compare density and theme while sorting and selecting fictional records. Selection follows each reference when the rows move.</p><div class="toolbar"><label>Density <select id="density"><option value="medium">Medium</option><option value="small">Small</option><option value="large">Large</option></select></label><label>Theme <select id="theme"><option value="light">Light</option><option value="dark">Dark</option></select></label></div><p id="selection" role="status">0 records selected</p><div class="scroll" tabindex="0" role="region" aria-label="Fictional follow-up records, horizontally scrollable"><table class="aksel-table aksel-table--zebra-stripes" id="records"><caption>Fictional follow-up records</caption><thead class="aksel-table__header"><tr class="aksel-table__row"><th class="aksel-table__header-cell" scope="col"><input id="all" type="checkbox" aria-label="Select all records"></th><th class="aksel-table__header-cell" scope="col">Reference</th><th class="aksel-table__header-cell" scope="col">Next activity</th><th class="aksel-table__header-cell" id="sort-header" scope="col" aria-sort="ascending"><button id="sort" type="button" class="aksel-table__sort-button">Waiting days ↑</button></th></tr></thead><tbody class="aksel-table__body" id="rows"></tbody></table></div><small>OpenDesign specimen using native Aksel 8.18.0 CSS and an explicit Arial fallback. Fictional data, no NAV identity or external actions.</small></main><script>const data=[{id:'DEMO-204',activity:'Confirm appointment preference',days:4},{id:'DEMO-218',activity:'Read the submitted example note',days:12},{id:'DEMO-231',activity:'Arrange an example callback',days:7}];let ascending=true;const selected=new Set(),all=document.querySelector('#all');function render(){const body=document.querySelector('#rows');body.replaceChildren();for(const r of [...data].sort((a,b)=>ascending?a.days-b.days:b.days-a.days)){const tr=document.createElement('tr');tr.className='aksel-table__row'+(selected.has(r.id)?' aksel-table__row--selected':'');const td=document.createElement('td');td.className='aksel-table__data-cell';const c=document.createElement('input');c.type='checkbox';c.setAttribute('aria-label','Select '+r.id);c.checked=selected.has(r.id);c.onchange=()=>{c.checked?selected.add(r.id):selected.delete(r.id);updateSelection();tr.classList.toggle('aksel-table__row--selected',c.checked)};td.append(c);const th=document.createElement('th');th.scope='row';th.className='aksel-table__header-cell';th.textContent=r.id;const activity=document.createElement('td');activity.className='aksel-table__data-cell';activity.textContent=r.activity;const days=document.createElement('td');days.className='aksel-table__data-cell aksel-table__data-cell--align-right';days.textContent=r.days;tr.append(td,th,activity,days);body.append(tr)}updateSelection()}function updateSelection(){all.checked=selected.size===data.length;all.indeterminate=selected.size>0&&selected.size<data.length;document.querySelector('#selection').textContent=selected.size+' records selected'}all.onchange=()=>{selected.clear();if(all.checked)data.forEach(r=>selected.add(r.id));render()};document.querySelector('#sort').onclick=()=>{ascending=!ascending;document.querySelector('#sort-header').setAttribute('aria-sort',ascending?'ascending':'descending');document.querySelector('#sort').textContent='Waiting days '+(ascending?'↑':'↓');render()};document.querySelector('#density').onchange=e=>document.querySelector('table').className='aksel-table aksel-table--zebra-stripes aksel-table--'+e.target.value;document.querySelector('#theme').onchange=e=>document.body.className=e.target.value;render();</script></body></html>

代码参考

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

Aksel 设计系统:AI Agent 设置

实现起点

预览中本地渲染了原生 CSS 8.18.0。React 的组合方式已通过源代码验证,但未单独构建。请保持版本一致;不要将 v7 navds 类与 v8 CSS 混用。Sources 中的完整可运行示例 ZIP 还包含准确的预览依赖项和完整文档。解压后,在该目录中运行 python3 -m http.server 8080,再打开 http://localhost:8080/nav-aksel.html。不要通过 file:// 打开基于模块的示例。

bash
npm install @navikt/[email protected] @navikt/[email protected]
# React entry:
# import "@navikt/ds-css";
# import { Table, HStack, Box } from "@navikt/ds-react";

适用于你项目的提示词

Agent 提示词
使用匹配的 8.18.0 CSS/React 包构建语义化的 Aksel v8 表格。保留标题、列标题和参考行标题。使用真实的 ax 令牌和 space-* 基础属性。提供带 aria-sort 的数值排序、基于稳定 ID 的复选框选择,以及支持不确定状态的全选功能。键盘交互不要依赖 onRowClick。支持浅色/深色角色令牌,并在窄屏幕上提供带标签的水平滚动区域。
05

Aksel 设计系统来源与范围

独立示例记录,不包含 NAV 身份标识。使用原生样式表,并注明字体回退方案。排序、选择和布局均属于应用行为;未展示真实收益或案例数据。