发现于 #3441 的实现过程,不在该 issue 的范围内(#3441 的正文把这颗按钮明确当作"已有名字"的参照物,用来证明另外三颗是遗漏),因此单独提。
现象
packages/collaboration/src/CommentThread.tsx 里每条评论回应条右侧的表情选择器按钮:
onReaction && React.createElement('button', {
style: styles.reactionPicker,
onClick: () => onReaction(comment.id, '👍'),
title: t('collaboration.addThumbsUp'),
}, '+'),
#3424 / #3438(objectstack#5506)给它接上了 collaboration.addThumbsUp,走的是 title。但对 button 来说,accname 算法先看内容(§2F "name from content"),title 是最后一档兜底(§2I)。这颗按钮有内容 '+',所以计算出来的可访问名就是 "+",title 从头到尾只是鼠标 tooltip,从来没有成为过它的名字。
屏幕阅读器读到的是"加号 按钮"/"plus button" —— 用户无从知道它做什么。title 被翻译了,可访问名没有。
证据(实测,非推演)
#3441 的 PR 里有一条现在就是绿的断言,直接钉住了这一点:
expect(screen.getByTitle('Add thumbs up')).toBeTruthy();
expect(screen.queryAllByRole('button', { name: 'Add thumbs up' })).toHaveLength(0);
getByRole(… { name }) 走的是 dom-accessibility-api 的 accname 实现。title 属性在(第一行绿),但没有任何按钮的可访问名是 Add thumbs up(第二行绿)。这两行同时成立,就是本 issue 的全部内容。
那条断言在 #3441 里的用途是区分 addThumbsUp(选择器)与新增的 reactThumbsUp(快捷 👍),顺手暴露了这个副作用;#3441 修的三颗按钮用的是 aria-label,正因为 aria-label 是唯一能盖过内容的那一档。
建议修法
把 title 换成(或补上)aria-label,复用同一个 key,不新增翻译:
title: t('collaboration.addThumbsUp'),
'aria-label': t('collaboration.addThumbsUp'),
两个都留着最稳:aria-label 给辅助技术,title 保留鼠标悬停提示(视觉用户目前唯一的线索),且仓内已有若干用例按 getByTitle('Add thumbs up') 定位它,不会被打断。
顺带需要判断的一个语义问题(留给处理人,不预设):这颗按钮的样式名叫 reactionPicker,但当前实现写死 onReaction(id, '👍') —— 它是个"选择器"的桩。名字到底该是 "Add thumbs up"(描述当前行为)还是 "Add reaction"(描述控件意图),取决于这个桩是否要继续做成真的选择器。当前的 addThumbsUp 描述行为是准确的,不改也自洽。
不属于本条的相邻情况
同一行的回应 chip 按钮(内容 👍 2,title 是 "2 reactions")同样是内容优先,但它的可访问名 "👍 2" 本身就是描述性的,读作"thumbs up 2 按钮",可用。不建议一并改动。
影响面
CommentThread 是 published exported component,仓内无消费方 —— 只有外部宿主会碰到,和 #3441 同一族。
发现于 #3441 的实现过程,不在该 issue 的范围内(#3441 的正文把这颗按钮明确当作"已有名字"的参照物,用来证明另外三颗是遗漏),因此单独提。
现象
packages/collaboration/src/CommentThread.tsx里每条评论回应条右侧的表情选择器按钮:#3424 / #3438(objectstack#5506)给它接上了
collaboration.addThumbsUp,走的是title。但对button来说,accname 算法先看内容(§2F "name from content"),title是最后一档兜底(§2I)。这颗按钮有内容'+',所以计算出来的可访问名就是"+",title从头到尾只是鼠标 tooltip,从来没有成为过它的名字。屏幕阅读器读到的是"加号 按钮"/"plus button" —— 用户无从知道它做什么。
title被翻译了,可访问名没有。证据(实测,非推演)
#3441 的 PR 里有一条现在就是绿的断言,直接钉住了这一点:
getByRole(… { name })走的是 dom-accessibility-api 的 accname 实现。title属性在(第一行绿),但没有任何按钮的可访问名是Add thumbs up(第二行绿)。这两行同时成立,就是本 issue 的全部内容。那条断言在 #3441 里的用途是区分
addThumbsUp(选择器)与新增的reactThumbsUp(快捷 👍),顺手暴露了这个副作用;#3441 修的三颗按钮用的是aria-label,正因为aria-label是唯一能盖过内容的那一档。建议修法
把
title换成(或补上)aria-label,复用同一个 key,不新增翻译:两个都留着最稳:
aria-label给辅助技术,title保留鼠标悬停提示(视觉用户目前唯一的线索),且仓内已有若干用例按getByTitle('Add thumbs up')定位它,不会被打断。顺带需要判断的一个语义问题(留给处理人,不预设):这颗按钮的样式名叫
reactionPicker,但当前实现写死onReaction(id, '👍')—— 它是个"选择器"的桩。名字到底该是 "Add thumbs up"(描述当前行为)还是 "Add reaction"(描述控件意图),取决于这个桩是否要继续做成真的选择器。当前的addThumbsUp描述行为是准确的,不改也自洽。不属于本条的相邻情况
同一行的回应 chip 按钮(内容
👍 2,title是 "2 reactions")同样是内容优先,但它的可访问名"👍 2"本身就是描述性的,读作"thumbs up 2 按钮",可用。不建议一并改动。影响面
CommentThread是 published exported component,仓内无消费方 —— 只有外部宿主会碰到,和 #3441 同一族。