HarmonyOS ArkUI 图标按钮无障碍:从“只念按钮”到完整页面读屏检查【鸿蒙心迹】
你是不是也在想——“鸿蒙这么火我能不能学会”答案是当然可以这个专栏专为零基础小白设计不需要编程基础也不需要懂原理、背术语。我们会用最通俗易懂的语言、最贴近生活的案例手把手带你从安装开发工具开始一步步学会开发自己的鸿蒙应用。不管你是学生、上班族、打算转行还是单纯对技术感兴趣只要你愿意花一点时间就能在这里搞懂鸿蒙开发并做出属于自己的App关注本专栏《零基础学鸿蒙开发》一起变强每一节内容我都会持续更新配图代码解释全都有欢迎点个关注不走丢我是小白酷爱学习我们一起上路 全文目录前言一、为什么只有一个图标时读屏很难知道它是什么意思二、无障碍文本和无障碍说明不是一回事三、accessibility group一条业务信息不要拆成五次朗读四、选中和禁用状态不能只靠颜色表达五、图片按钮应该把朗读信息放在哪里六、表单输入区不要只检查“能不能输入”七、把这些点放进一个最小页面八、做一次完整页面读屏检查容易理解错的几个地方开发经验总结前言一个只有图标、没有文字的操作按钮对视觉用户来说可能很直观心形代表收藏垃圾桶代表删除分享箭头代表分享。但切到屏幕朗读后如果组件只暴露了“按钮”这个类型而没有可朗读的名称用户得到的信息就可能只剩下“按钮”。这类问题并不需要重做页面。ArkUI 已提供无障碍文本、无障碍说明、无障碍分组、无障碍重要性等通用属性对于选择状态还可以优先使用 Checkbox、Toggle 等本身具有状态语义的组件。HarmonyOS 7 对应 API 26.0.0本文以 HarmonyOS 7 / API 26 为基线做一次从图标按钮到表单区域的完整页面无障碍补全。华为官方也已经提供“提升屏幕朗读无障碍体验”专题覆盖按钮标注、多维信息整体朗读、控件状态变化、自定义控件播报状态等场景。一、为什么只有一个图标时读屏很难知道它是什么意思先看一个常见写法Button({ type: ButtonType.Circle }) { Image($r(app.media.ic_favorite)) .width(24) .height(24) } .onClick(() { // 收藏操作 })这里视觉上已经是一个完整按钮但Image本身没有“收藏”这段文字。官方对无障碍文本的定义很明确当组件没有可供屏幕朗读的文本信息时可以通过accessibilityText提供无障碍文本如果组件本身已有文本设置的无障碍文本会作为朗读内容使用。accessibilityDescription则用于进一步解释操作及可能产生的后果。HarmonyOS 7 的 ArkUI API 变更资料中仍可以确认CommonMethod提供accessibilityGroup(value: boolean)、accessibilityText(value: string)、accessibilityDescription(value: string)、accessibilityLevel(value: string)等接口。所以这个问题的关键并不是“给图标起一个文件名”而是让真正承担交互的组件向无障碍服务暴露完整语义。可以改成Button({ type: ButtonType.Circle }) { Image($r(app.media.ic_favorite)) .width(24) .height(24) .accessibilityLevel(no) } .width(48) .height(48) .accessibilityText(收藏) .accessibilityDescription(将当前内容加入收藏) .onClick(() { // 收藏操作 })这里真正需要关注三件事。第一accessibilityText(收藏)回答的是“这是什么”。第二accessibilityDescription(将当前内容加入收藏)回答的是“执行后会发生什么”。第三图标只是按钮内部的视觉内容因此示例通过accessibilityLevel(no)避免它再成为一个没有独立交互价值的朗读目标。无障碍重要性支持auto、yes、no和no-hide-descendants等取值其中no表示当前组件不被无障碍辅助服务识别no-hide-descendants则会同时忽略当前组件及全部子组件。这里也能看出一个设计原则**不要把 Image 本身加上onClick就直接当按钮使用。**如果交互语义本来就是按钮优先使用Button承载点击行为再把Image放进 Button。官方 Button 指南明确支持 Button 作为容器添加图片、文字等子组件。二、无障碍文本和无障碍说明不是一回事accessibilityText和accessibilityDescription很容易被写成两句差不多的话.accessibilityText(删除) .accessibilityDescription(删除按钮)这种配置虽然有信息但第二句没有增加多少价值。更合理的思路是.accessibilityText(删除) .accessibilityDescription(删除当前草稿)对于风险更高的操作还可以把后果写清楚.accessibilityText(删除) .accessibilityDescription(删除当前草稿操作前会再次确认)官方文档对二者的职责划分也是如此无障碍文本负责提供组件本身缺少的文字信息无障碍说明用于补充仅靠组件属性和无障碍文本无法得知的操作后果存在说明时朗读会在组件文本之后继续播报说明。因此不建议把所有按钮都机械补成“XX按钮点击XX”。真正需要补的是用户无法从名称本身判断的信息。三、accessibility group一条业务信息不要拆成五次朗读页面中的另一个典型问题是一张信息卡片由多个Text拼成订单 待支付 68 元 今天 18:00 前支付如果这些信息属于同一个不可独立操作的业务单元让读屏逐个停留用户需要多次滑动才能知道这张卡片表达了什么。这种场景可以考虑无障碍分组Row() { Column({ space: 4 }) { Text(订单) Text(待支付) Text(68 元) Text(今天 18:00 前支付) } .alignItems(HorizontalAlign.Start) } .width(100%) .padding(16) .accessibilityGroup(true) .accessibilityText(订单待支付金额68元今天18点前支付)accessibilityGroup(true)的含义是把当前组件和子组件作为一个整体的可选中组件无障碍服务不再分别关注它的子组件内容。这很好用但也很容易用错。如果卡片里面还有“支付”“取消”两个真正需要独立操作的按钮就不应该简单把整张卡片全部 group 掉。否则子组件不再作为独立的无障碍目标反而可能损失操作入口。所以分组的判断标准不是“它们视觉上在一个 Row 里”而是这些子节点在无障碍交互中是否应该被当成一个整体。四、选中和禁用状态不能只靠颜色表达视觉页面经常用颜色区分状态蓝色表示选中灰色表示禁用实心心形表示已收藏。问题在于颜色和图标变化并不等于无障碍语义发生了变化。对于真正属于“选择”的交互优先考虑使用具有对应状态模型的标准组件。例如 Checkbox 从 API version 8 开始提供select(value: boolean)用来设置选中状态onChange返回状态变化结果。HarmonyOS 当前文档同时明确提供enabled控制组件是否可交互。例如State private receiveNotice: boolean false; Checkbox({ name: receiveNotice }) .select(this.receiveNotice) .accessibilityText(接收更新通知) .onChange((value: boolean) { this.receiveNotice value; })如果业务就是一个勾选项不建议为了视觉效果自己画一个Image再维护一份State最后还要额外想办法把状态暴露给无障碍系统。禁用状态同理。不要只是把按钮改成灰色Button(提交) .enabled(this.canSubmit)官方对enabled(false)的行为说明是组件进入不可交互状态不再响应点击、触摸、拖拽、按键、焦点和鼠标事件同时 UI 状态也会变化。对于自定义 Native ArkUI 节点官方还提供了ArkUI_AccessibilityState用于描述选中、勾选、禁用等无障碍状态该结构从 API version 12 开始提供。本文的 ArkTS 页面没有必要为了普通 Checkbox/Button 再下沉到 Native API但这个接口也说明了一个核心原则状态是无障碍信息的一部分而不仅仅是视觉样式。具体的屏幕朗读措辞可能随系统版本、组件和辅助服务而不同因此实际项目仍应在目标 HarmonyOS 版本和目标设备上逐项验证而不是根据界面颜色推断读屏结果。五、图片按钮应该把朗读信息放在哪里再看一个更完整的图片按钮Button({ type: ButtonType.Circle }) { Image($r(app.media.ic_share)) .width(24) .height(24) .accessibilityLevel(no) } .width(48) .height(48) .accessibilityText(分享) .accessibilityDescription(打开分享面板) .onClick(() { // 打开分享面板 })这里把无障碍文本设置在Button上而不是设置在内部Image上。原因很直接真正可以执行操作的是 Button。Image 只是它的视觉表现。如果把 Image 和 Button 都做成可识别节点就可能出现两个焦点如果只给 Image 写“分享”而 Button 本身仍没有名称组件树中的交互语义又会变得割裂。ArkUI 官方针对无障碍场景还提供了代码检查规则要求自定义交互组件通过accessibilityRole声明组件类型例如按钮、编辑框。对于本文这种标准Button场景可以直接使用标准组件如果业务必须用Column、Row等组件自己实现交互则还需要额外关注角色语义而不是只有一个onClick就结束。六、表单输入区不要只检查“能不能输入”一个页面做无障碍检查时输入框经常被漏掉因为TextInput本身已经能够获得焦点、输入文字看起来没有问题。但读屏用户还需要知道三个信息这是哪个字段、现在是什么状态、填写它有什么要求。最小表单可以这样组织State private email: string ; Column({ space: 8 }) { Text(邮箱地址) .fontSize(14) TextInput({ text: this.email, placeholder: nameexample.com }) .width(100%) .accessibilityDescription(用于接收更新通知) .onChange((value: string) { this.email value; }) Button(提交) .enabled(this.email.length 0) .accessibilityDescription( this.email.length 0 ? 提交当前表单 : 请先填写邮箱地址 ) } .alignItems(HorizontalAlign.Start)这里特意保留了可见的“邮箱地址”标签而不是只依赖 placeholder。placeholder 是输入提示并不应该承担页面上全部的字段说明。另一个需要谨慎的地方是accessibilityText官方定义指出当组件本身已有文本信息时无障碍文本可以替代原有文本进行播报。 对编辑组件来说如果随意用固定的accessibilityText(邮箱地址)覆盖内容就需要特别检查输入后的实际朗读结果。因此表单不要套用“所有组件都加 accessibilityText”的机械规则而应该以最终读屏顺序和实际播报内容为准。七、把这些点放进一个最小页面下面代码把图标按钮、信息分组、Checkbox 状态、输入框和禁用按钮放在同一页。代码按照 HarmonyOS 7 / API 26 当前官方接口组织其中ic_favorite、ic_share是示例应用自己的图片资源名需要在工程resources/base/media中准备对应资源。Entry Component struct AccessibilityDemo { State private receiveNotice: boolean false; State private email: string ; build() { Scroll() { Column({ space: 20 }) { Text(文章详情) .fontSize(24) .fontWeight(FontWeight.Bold) Row({ space: 12 }) { Button({ type: ButtonType.Circle }) { Image($r(app.media.ic_favorite)) .width(24) .height(24) .accessibilityLevel(no) } .width(48) .height(48) .accessibilityText(收藏) .accessibilityDescription(将当前文章加入收藏) .onClick(() { // 收藏业务 }) Button({ type: ButtonType.Circle }) { Image($r(app.media.ic_share)) .width(24) .height(24) .accessibilityLevel(no) } .width(48) .height(48) .accessibilityText(分享) .accessibilityDescription(打开分享面板) .onClick(() { // 分享业务 }) } Row() { Column({ space: 4 }) { Text(阅读进度) Text(第 3 章) Text(约 8 分钟) } .alignItems(HorizontalAlign.Start) } .width(100%) .padding(16) .accessibilityGroup(true) .accessibilityText(阅读进度第3章约8分钟) Row({ space: 8 }) { Checkbox({ name: receiveNotice }) .select(this.receiveNotice) .accessibilityText(接收更新通知) .onChange((value: boolean) { this.receiveNotice value; }) Text(接收更新通知) } .width(100%) Column({ space: 8 }) { Text(邮箱地址) .fontSize(14) TextInput({ text: this.email, placeholder: nameexample.com }) .width(100%) .accessibilityDescription(用于接收更新通知) .onChange((value: string) { this.email value; }) } .alignItems(HorizontalAlign.Start) .width(100%) Button(提交) .width(100%) .enabled(this.email.length 0) .accessibilityDescription( this.email.length 0 ? 提交当前表单 : 请先填写邮箱地址 ) } .padding(20) .width(100%) .alignItems(HorizontalAlign.Start) } .width(100%) .height(100%) } }这个示例没有调用 Accessibility Kit 的状态查询或主动播报接口也没有新增module.json5权限。这里解决的是 ArkUI 组件自身的无障碍语义问题主要依赖 ArkUI 通用属性和标准组件。Accessibility Kit 更偏向无障碍状态查询、无障碍事件发送等能力ArkUI 则负责组件层面的无障碍文本、说明等信息。八、做一次完整页面读屏检查代码写完并不代表无障碍检查结束。这个场景最有效的排查方式是把页面当成一个完全不看的用户从第一个焦点一直滑到最后一个焦点。建议按下面的顺序检查先查无名控件。所有纯图标按钮、图片操作入口、自定义点击区域确认读屏能回答“这是什么”。再查重复焦点。Button 内部的装饰 Image、卡片里的重复文字有没有被额外聚焦需要整体表达的信息是否适合accessibilityGroup(true)。再查角色和状态。按钮是不是按钮选择项是否使用了合适的标准选择组件禁用是否真的调用了enabled(false)而不是只改变透明度或颜色。检查操作后果。删除、提交、跳转、打开弹窗等操作如果名称本身不足以解释后果再补accessibilityDescription。检查表单。输入框是否能理解字段用途错误、必填、禁用等状态是否仅存在于视觉样式中。最后完整走焦。从页面顶部连续左右滑动观察是否存在焦点遗漏、重复、顺序不自然或必须“猜图标”的地方。华为官方的“提升屏幕朗读无障碍体验”指南本身就把按钮标注、多维信息整体朗读、多 UI 控件组合、禁用屏幕朗读焦点、控件状态变化、内容动态变化和自定义控件走焦顺序等列为独立场景。换句话说无障碍检查不能只盯着一个accessibilityText属性而应该检查整棵交互树。容易理解错的几个地方accessibilityGroup(true)不是“优化朗读”的万能开关。它会让无障碍服务不再分别关注子组件因此包含独立按钮的区域不能随意整体分组。accessibilityLevel(no)和no-hide-descendants也不是一回事。前者针对当前组件后者会把当前组件以及子组件一起从无障碍识别范围中排除。禁用按钮不要只设置.opacity(0.4)。视觉变灰不会自动等价于交互禁用ArkUI 的enabled(false)才会使组件进入不可交互状态。有状态的控件尽量不要全部从Row Image onClick开始手写。Checkbox 已有明确的select状态接口标准组件能够表达业务语义时优先让组件模型承担状态再考虑视觉定制。还有一点很重要本文代码依据官方接口组织但没有在具体 HarmonyOS 工程中替你完成编译和真机读屏验证因此不应把“接口存在”直接等同于“目标设备上的每一句朗读措辞已经验证”。发布前仍应使用项目实际的 API 配置、目标设备和屏幕朗读服务完整走一遍页面。开发经验总结做 ArkUI 页面无障碍补全可以把问题压缩成四个词名称、角色、状态、关系。图标按钮缺的是名称就补accessibilityText操作结果不明确再补accessibilityDescription。多个文本共同表达一条业务信息时再判断是否应该使用accessibilityGroup。装饰性子节点不应该制造额外焦点可以通过无障碍重要性控制。对于勾选、开关、禁用等状态优先使用能够真实表达状态的标准组件和enabled、select等接口而不是只改变颜色。HarmonyOS 7 对应 API 26.0.0本文使用的 ArkUI 通用无障碍属性在 API 26 当前接口中仍然存在Checkbox 等标准组件也继续提供明确的状态接口。真正值得在项目里形成习惯的不是“看到 Image 就加 accessibilityText”而是每做完一个页面都关掉视觉上的先验信息从第一个无障碍焦点走到最后一个它是谁、现在是什么状态、能做什么、操作之后会怎样。只要其中一个问题需要用户猜这个页面就还有继续补充语义的空间。❤️ 如果本文帮到了你…请点个赞让我知道你还在坚持阅读技术长文请收藏本文因为你以后一定还会用上如果你在学习过程中遇到bug请留言我帮你踩坑

相关新闻

Agent接入业务系统的关键:上下文组织与权限控制实战

Agent接入业务系统的关键:上下文组织与权限控制实战

把 Agent 从调试终端里搬出来、真正跑进业务流程的那一刻,你会发现最需要认真对待的其实不是模型本身,而是两件事:上下文怎么组织,权限怎么控制。这两个问题处理不好,Demo 阶段表现再抢眼,到了生产环境也会…

2026/10/13 10:10:30 阅读更多 →
TyHGB复合指标在CHARLS健康评估中的应用与实现

TyHGB复合指标在CHARLS健康评估中的应用与实现

1. 项目背景与核心价值TyHGB这个复合指标在CHARLS领域的应用确实是一片尚未开发的蓝海。作为长期关注健康指标研究的从业者,我注意到传统TyG指数(甘油三酯葡萄糖指数)虽然被广泛用于评估胰岛素抵抗,但在老年人群中的应用存在明显局…

2026/10/13 10:10:30 阅读更多 →
T3 Stack全栈实践:tRPC与Prisma打通端到端类型安全

T3 Stack全栈实践:tRPC与Prisma打通端到端类型安全

最近在折腾全栈项目的时候,我把研究重点放在了 t3code 这个代号下的整套技术组合上。如果你也关注过 Next.js 生态,T3 Stack 这个名字多半不陌生,它把 Next.js、TypeScript、tRPC、Prisma、Tailwind CSS、NextAuth 这六样东西打包成一套开箱即…

2026/10/13 10:09:29 阅读更多 →

最新新闻

MySQL慢查询定位与索引设计:EXPLAIN与B+树实战全解析

MySQL慢查询定位与索引设计:EXPLAIN与B+树实战全解析

接手线上业务系统这几年,最让我头疼的问题之一就是MySQL慢查询。明明功能开发完了、测试也过了,一到流量高峰期,几个核心接口突然就卡了几秒,数据库CPU飙高,紧接着就是连接数打满、应用报错。排查下来,十有…

2026/10/13 11:00:03 阅读更多 →
ASIO2WASAPI:让普通声卡也能跑低延迟ASIO的桥接实践

ASIO2WASAPI:让普通声卡也能跑低延迟ASIO的桥接实践

简介:ASIO2WASAPI 是面向 Windows Vista 及以上系统的开源音频驱动方案,为音乐制作人与音频工程师提供硬件无关的 ASIO 支持。它借助中间层将 ASIO 协议和 Windows 原生 WASAPI 结合,用独占模式逼近硬件极限延迟,解决无专用音频接…

2026/10/13 11:00:03 阅读更多 →
JumpServer统一纳管PostgreSQL:从资产配置到安全审计的完整实践

JumpServer统一纳管PostgreSQL:从资产配置到安全审计的完整实践

搞了这么多年运维,数据库资产一直是权限管理里最让人头疼的一环。尤其PostgreSQL这种逻辑库多、角色权限细的系统,直接让人连生产库,账号密码满天飞不说,出事了你连谁干的都查不到。前阵子刚把一套PostgreSQL完整接进了JumpServer…

2026/10/13 11:00:03 阅读更多 →
MySQL Workbench 从下载到实战:安装避坑、连接配置与日常管理技巧

MySQL Workbench 从下载到实战:安装避坑、连接配置与日常管理技巧

最早学数据库那会儿,我一直在黑窗口里敲命令。建表、导数据、改权限全靠手打,一条语句写错就得整条回滚,效率低不说,眼睛也是真遭罪。后来换了 MySQL Workbench,整个体验完全不一样:不用背那么多命令&#…

2026/10/13 11:00:03 阅读更多 →
快速搭建规范开源项目:从零构建可协作可维护的GitHub仓库

快速搭建规范开源项目:从零构建可协作可维护的GitHub仓库

1. 为什么“快速搭建规范开源项目”这件事,比你想象中更值得花时间 “快速在GitHub搭建一个规范的开源项目(一)”——这个标题里藏着三个被新手普遍低估的关键词: 快速 、 规范 、 (一) 。不是“建个…

2026/10/13 11:00:03 阅读更多 →
用帕累托图做线上问题优先级排序:从频次统计到加权决策

用帕累托图做线上问题优先级排序:从频次统计到加权决策

作为负责线上稳定性的工程师,我每天到工位后的第一件事,不是看代码,而是先扫一眼昨夜的问题清单。以前团队排故障优先级基本靠嗓门,谁在群里吼得凶就修谁的;直到我们用帕累托图把问题频次和影响摊开做排序,…

2026/10/13 10:58:59 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 14:48:49 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →