J2.15.4theme switch focus设计研究

用户切换主题时的状态与焦点不应丢失

别名: 主题切换保焦点 · persist state across theme · color-scheme remount

概念解释

切换深色浅色时如果整页重绘,正在填的表、键盘所在的控件、滚动位置、已打开的菜单都可能被重置。主题是皮肤,不该是一次导航。切换主题不丢状态与焦点要求:外观变了,用户还停在刚才那个控件上,刚才填的还在,刚才卷到的地方还在。

低视力用户会在任务中途改对比或改外观,因为当前这一屏读不清。若一改就丢焦点,他们被罚回页顶,等于把辅助设置变成了破坏性操作。

机制

许多实现把主题写在根节点的 class 或属性上,框架为了换样式树选择卸载整棵组件树再挂上去。卸载会拆掉:焦点、受控输入里还没提交的值、滚动容器的偏移、弹出层的打开态、实时区域里正在读的那一句。浏览器自己的外观切换(系统深色)通常只重算样式,不卸树;产品内的主题按钮若走「改路由 / 整页刷新 / 重挂根」,损失就比系统切换大。

焦点丢失还有一层无障碍代价。键盘用户的「我在哪」全靠焦点;阅读器的浏览位置若随着重挂被重置,用户会听到页头再来一遍。表单里未提交的字段被清空,则是数据丢失,不只是视觉换肤。

怎么研究

在填写到一半的表单、打开的对话框、列表中部的焦点上,触发产品内主题开关与系统外观开关,记录焦点元素、字段值、滚动偏移、对话框是否仍打开。

自变量:切换实现(只改根属性 / 整页刷新 / 卸载重挂)、切换来源(产品按钮 / 系统)。 因变量:焦点是否仍在原控件、未提交值是否还在、滚动偏移差、对话框是否被关掉、阅读器是否重读页头。

键盘-only 是必需条件:指针用户看得到画面还在,不容易发现焦点已经回到地址栏。把「外观确实换了」和「任务位置还在」分成两个观察量,前者是换肤成功,后者才是这条判据。

边界

切换主题若被设计成「重新登录才生效」,那是产品策略,应在开关上预先声明,而不是在填表中途静默执行。某些画布或 WebGL 场景换色必须重建上下文,状态要由应用自己序列化再灌回去,不能指望 DOM 焦点还在。跨文档的整页刷新(用户点了会跳走的链)本来就会丢状态,与主题无关。系统在应用暂停时改外观(手机进后台再回来),有的系统会在恢复时重绘,焦点策略要按平台生命周期另测。

怎么落地

  • 主题开关只改根上的外观属性或变量,不要为换肤刷新页面或卸载整棵树。
  • 换肤前后比较 document.activeElement(或平台等价物):应是同一个控件,而不是回到文档根或地址栏。
  • 未提交的输入、打开的浮层、滚动位置列入换肤回归;任一项被重置都按功能回归失败处理。
  • 验证:用键盘把焦点停在表单中部一个字段,填几个字,打开主题开关。外观变了之后,焦点仍在该字段、字还在、不必从页头重新 Tab。焦点丢了或字段被清空,记失败。

延伸

  • 同组J2.15.1 深色模式下的对比度需要重新计算而非沿用浅色模式数值 · J2.15.2 系统强制的高对比模式可能覆盖自定义颜色导致设计失真 · J2.15.3 图片与图标资源需要针对深色背景准备适配版本
  • 相邻J3.02 焦点顺序与焦点陷阱 · J5.12 动态内容的播报 · J5.13 系统级辅助功能设置
  • 站内检索theme switch focus · persist state across theme · color-scheme remount

同组卡片

快捷操作

分享

分享当前页面

ios_share

https://hci.top/zh/handbook/J2.15.4