跨平台与移动端 UI · 新资源

Ionic Framework 设计系统.

原生 Ionic 阅读偏好设置界面,包含经过验证的配色角色、iOS 和 Material 范围滑块的几何样式、真实的分段控件与开关行为,以及可根据字体、字号和纸张选项调整的文章。

OpenDesign 指南9 个章节25 条参考条目原始应用指南
01

Ionic Framework 设计系统界面预览

切换字体、使用键盘调整字号、切换暖色纸张底色,并保存本地偏好设置快照。

阅读偏好设置打开完整示例
Ionic Vue/Core 9.0.6、Vue 3,明确指定 iOS 模式。原生 Web 组件在本地打包。· 实现参考
02

Ionic Framework 设计系统设计参考

已验证 Ionic Vue/Core 9.0.6。核心颜色取自已安装的 core.css。演示明确选择 iOS 模式。阅读排版、纸张颜色和周边间距均为应用自身的设计选择,并非 Ionic 默认值。

浅色主题的默认语义颜色角色

来源
名称 / 规则值 / 配置用途
--ion-color-primary#0054e9 原生主要控件。
--ion-color-primary-rgb0, 84, 233用于基于不透明度进行计算的 RGB 通道值。
--ion-color-primary-contrast#fff主要颜色上的文本与图标对比度。
--ion-color-primary-shade#004acd 加深后的主要颜色变体。
--ion-color-primary-tint#1a65eb 提亮后的主要颜色变体。
--ion-color-secondary#0163aa 次要角色。
--ion-color-tertiary#6030ff 第三级颜色角色。
--ion-color-success#2dd55b 成功角色。
--ion-color-warning#ffc409 警告角色。
--ion-color-danger#c5000f 危险角色。

按模式区分的原生范围控件尺寸

来源
名称 / 规则值 / 配置用途
iOS --bar-height4px编译后的 iOS 范围控件默认值。
iOS --knob-size26px编译后的 iOS 滑块尺寸。
MD --bar-height2px编译后的 Material Design 模式默认值。
MD --knob-size18px编译后的 Material Design 滑块尺寸。
Application min / max / step16 / 26 / 1整数形式的阅读字号;对应实际范围控件属性。
snaps / ticks / pintrue / true / true显示刻度和格式化后的字号反馈。

原创阅读与布局比例

来源
名称 / 规则值 / 配置用途
Reading fontGeorgia, serif OR system-ui, sans-serif由原生分段控件控制;字体取自设备已有字体。
Reading size16–26px; default 18px直接应用于文章。
Reading line-height1.65原创的舒适正文行宽。
Article heading1.9em / 1.15; 1.6em below 360px随读者选择的正文大小缩放。
Control/body fontsystem-ui, sans-serif明确指定应用字体。
Spacing10 / 12 / 14 / 16 / 20 / 22 / 24 / 28 / 32px具体的原创样式表数值,并非声称属于 Ionic 的比例系统。
Layout300px settings + flexible article; stack at 760px两列均使用 min-width:0。
Paper roles#fff9eb warm; #ffffff white; #24362e ink原创内容颜色,与原生控件角色分开设置。
Card radius16px原创的外围面板尺寸。
03

Ionic Framework 设计系统完整指南

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

DESIGN-ionic.md

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

下载指南

Ionic Framework 设计系统:审慎选择渲染模式

审慎选择渲染模式

Ionic 通过框架集成提供 Web 组件。此示例使用 Ionic Vue 9.0.6,并在 IonicVue 配置中将 mode 设为 ios。这样一来,无论使用哪种桌面浏览器查看页面,segment、toggle、range 和按钮都能保持统一的平台风格。mode 是组件渲染方式的选择;它不会将页面变成原生移动应用。

摘自本 OpenDesign 指南

此示例特意使用普通的 main 元素,而不是全屏的 IonApp/IonContent 外壳。这样,组件示例就能在嵌入式资源页面中按内容调整尺寸。实际的 Ionic 路由应用应遵循框架的页面和路由结构,并在过渡效果需要时使用 IonPage。

阅读配套规范

Ionic Framework 设计系统:Ionic 颜色由一组相关变量构成

Ionic 颜色由一组相关变量构成

已安装的核心样式表将 primary 定义为 #0054e9,并提供单独的 RGB 通道、对比色、阴影色和浅色变体值。组件可在不同状态下使用这些相关值。只替换基础十六进制颜色可能导致其他状态不一致;自定义品牌色应定义完整的一组颜色值。

此示例保留了原生控件的默认 primary 颜色。暖纸色是单独的应用界面表面,颜色为 #fff9eb,文章文字则保持为 #24362e。将页面切换为白色只会改变阅读背景,不会悄然更改控件配色,也不代表实现了 Ionic 的完整深色配色方案。

阅读配套规范

Ionic Framework 设计系统:让读者的字体选择效果清晰可见

让读者的字体选择清晰可见

此分段控件可在 Georgia 和 system-ui 之间切换文章字体。控件本身仍使用 system-ui,确保偏好设置只影响指定的阅读内容,不会意外改变标签和控件尺寸。示例不会请求外部字体,而是使用相应的本地字体栈。

文字大小为 16 到 26 像素之间的整数。文章标题按此字号进行比例缩放,行高保持为 1.65。在宽度小于 360px 时,标题的缩放比例降至 1.6em,因此即使嵌入栏较窄,最大字号仍然易于阅读。这些是应用自定义值,与 Ionic 组件默认值明确区分。

阅读配套规范

Ionic Framework 设计系统:分段控件具有受控的选中状态和原生语义

分段控件应具备受控的选中状态和原生语义

IonSegment 接收当前的 face 值和两个 IonSegmentButton 子项。其 ionChange 事件会从 event.detail.value 更新模型。每个按钮都有不同且稳定的值:serif 或 sans,显示标签则说明对应选项。使用 aria-labelledby 为整个控件提供标签。

实际的无障碍树会将其呈现为包含已选中标签的 tablist,而不是普通按钮组。因此,本地交互测试会定位原生的“无衬线”标签页,并验证阅读字体随之改变。仅仅将两个按钮样式设计成分段控件的外观,并不能实现相同的选中行为。

阅读配套规范

Ionic Framework 设计系统:将范围事件和约束作为一套完整约定

将范围控件事件和约束作为统一契约

IonRange 明确设置 min、max 和 step;依赖其默认的 0 到 100 范围,无法表达实用的阅读字号。启用吸附和刻度可以显示可选步进值,pin 格式化函数则会在交互时显示的数值后追加 px。拖动结束后,控件下方持续显示的字号标签仍清晰可读。

事件处理程序使用 ionChange,并将其值转换为数字。这适用于单滑块;双滑块范围会返回不同形态的值,需要单独处理。编译后的 iOS range 使用 26 像素滑块和 4 像素轨道,而 Material 模式使用 18 像素和 2 像素。这些差异会如实记录,不会被简化成虚构的通用 Ionic 令牌。

  1. 聚焦字号滑块,按 8 次右箭头键,将字号调至 26px。
  2. 选择“无衬线”,并关闭“暖纸色”。
  3. 保存偏好设置,并核对快照中的确切字体、字号和纸张样式。

阅读配套规范

Ionic Framework 设计系统:布尔值控制的纸张选项应立即更新界面表面

切换纸张底色时,应立即更新界面

IonToggle 从 warm 模型接收 checked 值。其事件会提供 detail.checked,并将其直接赋给对应的布尔状态。可见标签“暖纸色”属于原生开关,旁边的说明则告知读者此选项会改变文章背景。

warm 类会改变文章背景,但保留边框和文章内容,使对比具有意义。这样也能避免将纸张色调偏好与平台级的浅色/深色设置混为一谈;后者需要协调更多 Ionic 界面表面和文字变量。

阅读配套规范

Ionic Framework 设计系统:将已应用的偏好设置与已保存的快照区分开

区分已应用的偏好设置与已保存的快照

每项设置都会立即应用于文章。“保存偏好设置”会在本地响应式状态中记录一份易读的快照,并在快照与当前设置一致时禁用按钮。对三个模型进行监听;任何一项发生变化,都会清除提示,避免旧的确认信息描述新的组合。

“恢复默认设置”会恢复 serif、18 像素和暖纸色,然后清除已保存的提示。状态说明明确指出,这些偏好设置仅应用于此预览。此操作背后没有 localStorage 持久化、账户设置或原生偏好设置插件;重新加载后会恢复默认值。

阅读配套规范

Ionic Framework 设计系统:保留原生 Shadow DOM 控件,同时为整体布局添加样式

保留原生 Shadow DOM 控件,同时为整体布局添加样式

range 带有可见的“字号”标签,toggle 内含文字标签,segment 则标记为“字体”。原始插图设为 aria-hidden。保存反馈使用 role=status,文章仍是普通的语义化 HTML,因此其中的标题和段落可遵循读者常规的文档导航方式。

Ionic 组件会将内部标记封装在 Shadow DOM 中。本示例使用公开属性、事件和文档中说明的 CSS 自定义属性,而不是查询私有内部类。外围页面采用内容高度和零最小宽度;在 280px 宽度下检查,可以发现独立手机截图可能遗漏的嵌入式宽度问题。

  • 在原生组件上保留标签关联关系。
  • 使用公开属性和事件,而不是修改 Shadow DOM 内部结构。
  • 同时检查键盘尺寸变化和实时文章。

阅读配套规范

Ionic Framework 设计系统:安装 Vue 集成并引入核心 CSS

安装 Vue 集成并引入 Core CSS

完整入口会注册 IonicVue,并在原始样式表之前导入 @ionic/vue/css/core.css。已安装的 Vue 包也会解析 vue-router,因此可复现的依赖安装命令中包含 vue-router,尽管这个嵌入式示例并未配置导航。遗漏该对等依赖会导致本地打包时无法解析依赖。

两个完整示例提供了 App.vue 和 style.css。标准 Vite Vue 项目会编译单文件组件(SFC)及其原生组件导入。独立资源预览会在本地打包生成的 JavaScript 和 CSS,包括组件实现,因此更改控件无需请求外部 CDN。

阅读配套规范

Ionic Framework 设计系统组件示例

完整的阅读偏好 SFC

原生 IonSegment、IonRange、IonToggle 和 IonButton 用于控制一篇原创短文。

vue
<script setup>
import {ref,computed,watch} from 'vue';
import {IonSegment,IonSegmentButton,IonLabel,IonRange,IonToggle,IonButton,IonChip} from '@ionic/vue';
const face=ref('serif'),size=ref(18),warm=ref(true),saved=ref('');
const family=computed(()=>face.value==='serif'?'Georgia, serif':'system-ui, sans-serif');
watch([face,size,warm],()=>saved.value='');
function save(){saved.value=`Saved locally: ${face.value}, ${size.value}px, ${warm.value?'warm':'white'} paper.`}
function reset(){face.value='serif';size.value=18;warm.value=true;saved.value=''}
</script>
<template>
<main class="reader-shell">
<header><p class="eyebrow">A QUIETER READING SPACE</p><h1>Make room for the words.</h1><p>Adjust this short essay to your reading preferences. The sample changes as you move the controls.</p></header>
<div class="reader-layout"><section class="preferences" aria-labelledby="preferences-title"><h2 id="preferences-title">Reading settings</h2><p class="label" id="face-label">Typeface</p>
<IonSegment :value="face" @ionChange="face=$event.detail.value" aria-labelledby="face-label"><IonSegmentButton value="serif"><IonLabel>Serif</IonLabel></IonSegmentButton><IonSegmentButton value="sans"><IonLabel>Sans</IonLabel></IonSegmentButton></IonSegment>
<IonRange :value="size" @ionChange="size=Number($event.detail.value)" :min="16" :max="26" :step="1" :snaps="true" :ticks="true" :pin="true" label="Text size" label-placement="stacked" :pin-formatter="v=>`${v}px`"/><p class="scale"><span>16px</span><strong>{{size}}px</strong><span>26px</span></p>
<div class="paper-toggle"><IonToggle :checked="warm" @ionChange="warm=$event.detail.checked" justify="space-between">Warm paper</IonToggle><p>Soft ivory or a white page. The controls keep their own contrast.</p></div>
<IonButton expand="block" @click="save" :disabled="!!saved">Save preferences</IonButton><IonButton expand="block" fill="clear" @click="reset">Restore defaults</IonButton><p class="save-result" role="status">{{saved||'Preferences apply to this preview only.'}}</p></section>
<article class="reading-paper" :class="{warm}" :style="{fontFamily:family,fontSize:size+'px'}"><div class="paper-art" aria-hidden="true"><span></span><i></i><b></b></div><p class="article-kicker">FIELD NOTES · 03</p><h2>The useful pause</h2><p>There is a small garden between the library and the river. Its benches face away from the busiest path, toward a row of young trees.</p><p>On an ordinary afternoon, the place asks very little. You can read a paragraph twice, let a conversation settle, or watch the shadow of a leaf move across the page.</p><p>Good reading spaces leave that choice with the reader. A comfortable line, a familiar letterform, and a little breathing room can make a page easier to return to.</p><footer><IonChip outline>Original sample essay</IonChip><span>{{size}}px · {{face==='serif'?'Georgia':'System sans'}} · 1.65 line height</span></footer></article></div>
</main>
</template>

代码参考

  • 范围值通过 ionChange 提交;e.detail.value 会转换为数字。
  • 更改任一偏好都会清除已保存的快照。
  • 保存操作使用本地响应式状态,不涉及设备存储或服务器请求。

完整的原创布局样式表

采用内容高度嵌入式布局和窄屏纵向排列;读者可选择字体样式,无需访问组件的 Shadow DOM。

css
html,body,#app{height:auto;min-height:0;margin:0}*{box-sizing:border-box}body{font-family:system-ui,sans-serif;color:#24362e;background:#f2f5f3}.reader-shell{max-width:1120px;margin:auto;padding:32px}.eyebrow{font-size:11px;letter-spacing:.14em;font-weight:700;color:#52695c}h1{font-size:34px;line-height:1.15;max-width:660px;margin:12px 0}header>p:last-child{font-size:15px;line-height:1.6;max-width:660px;color:#56675e}.reader-layout{display:grid;grid-template-columns:300px minmax(0,1fr);gap:24px;margin-top:28px}.preferences{background:white;border:1px solid #dbe3de;border-radius:16px;padding:22px;align-self:start;min-width:0}.preferences h2{font-size:19px;margin:0 0 22px}.label{font-size:14px;font-weight:600;margin-bottom:10px}ion-segment{margin-bottom:20px}ion-range{padding:12px 0 0;--bar-height:4px}.scale{display:flex;justify-content:space-between;font-size:12px;color:#52695c;margin:0 0 24px}.paper-toggle{border-top:1px solid #e4e9e6;padding-top:20px;margin-bottom:20px}.paper-toggle ion-toggle{width:100%;font-size:14px}.paper-toggle p{font-size:12px;line-height:1.6;color:#5a6b61}.save-result{font-size:12px;line-height:1.6;color:#46614f;min-height:38px}.reading-paper{background:white;border:1px solid #dce3dd;border-radius:16px;padding:28px;line-height:1.65;min-width:0;overflow-wrap:anywhere;transition:background .2s}.reading-paper.warm{background:#fff9eb}.reading-paper h2{font-size:1.9em;line-height:1.15;margin:14px 0 24px;font-weight:400}.reading-paper p{margin:0 0 1.2em}.article-kicker{font-family:system-ui,sans-serif;font-size:10px;letter-spacing:.15em}.paper-art{height:112px;background:#dce8d9;border-radius:8px;position:relative;overflow:hidden;margin-bottom:24px}.paper-art span{position:absolute;width:150px;height:150px;background:#a4baa2;border-radius:50%;right:15%;top:35px}.paper-art i{position:absolute;width:130px;height:70px;background:#f3e0a8;border-radius:50% 50% 0 0;right:25%;top:48px}.paper-art b{position:absolute;width:60px;height:130px;transform:rotate(24deg);background:#64816b;left:15%;top:38px;border-radius:50% 50% 0 0}.reading-paper footer{font:11px/1.6 system-ui,sans-serif;border-top:1px solid #deded3;padding-top:18px;display:flex;gap:12px;flex-wrap:wrap;align-items:center}.reading-paper ion-chip{font-size:11px;margin:0}@media(max-width:760px){.reader-shell{padding:20px}.reader-layout{grid-template-columns:minmax(0,1fr)}h1{font-size:29px}}@media(max-width:360px){.reader-shell{padding:14px}.preferences,.reading-paper{padding:16px}.reader-layout{gap:18px}.reading-paper h2{font-size:1.6em}}

代码参考

  • 范围控件使用文档中说明的 --bar-height 自定义属性。
  • 所有文章插图均为原创 CSS,并标记为装饰性内容。
04

Ionic Framework 设计系统 Agent 设置

实现起点

已验证 Ionic Vue/Core 9.0.6。完整 SFC 和样式表见上文;vue-router 作为集成依赖安装,但预览中没有路由页面。

javascript
// Start with: npm create vite@latest ionic-reader -- --template vue
// cd ionic-reader && npm install
// npm install @ionic/[email protected] @ionic/[email protected] vue-router@4
// Save the complete examples as src/App.vue and src/style.css.
// src/main.js:
import {createApp} from 'vue';
import {IonicVue} from '@ionic/vue';
import '@ionic/vue/css/core.css';
import './style.css';
import App from './App.vue';
createApp(App).use(IonicVue, {mode:'ios'}).mount('#app');
// The Vite index.html must contain:
// <div id="app"></div><script type="module" src="/src/main.js"></script>
// Run: npm run dev

适用于你项目的提示词

Agent 提示词
使用 Ionic Vue/Core 9.0.6 的显式 iOS 模式,构建提供的阅读偏好示例。保留原生 Segment、Range、Toggle 和 Button 控件,并让它们分别控制字体选择、文本大小、纸张外观和文章样式。将字号范围维持在 16–26px,并在本地已保存的偏好快照中反映更改。包含 IonicVue 设置、所需的 CSS 和 vue-router 对等依赖;保留内容高度布局,不要在嵌入区域中添加全屏外壳。不会上传检查数据,也不会远程更改账户。
05

Ionic Framework 设计系统来源与范围

Ionic Vue/Core 9.0.6,iOS 模式。原创短文、插图、阅读比例和暖纸色彩。保存使用本地响应式状态,不会在重新加载后保留。此嵌入式组件示例并非完整的路由应用或原生设备 Ionic 应用。