语义正确的工具栏容器应使用,禁用元素;需设tabindex="0"、手动聚焦、避免execcommand在markdown场景中误用,并通过selectionchange监听与querycommandstate同步按钮状态。

直接用 <div role="toolbar"> + <code>contenteditable 容器就能搭出可用的文档工具栏,但必须补全 aria-label、显式管理焦点、并避开 execCommand 在 Markdown 场景下的语义错位——否则按钮点不动、格式乱套、光标消失是常态。
怎么写语义正确的工具栏容器
HTML 没有 <toolbar></toolbar> 元素,浏览器不识别它。硬写会丢失可访问性,屏幕阅读器读不出用途。
- 必须用合法容器,比如
<div> 或 <code><section></section> - 必须加
role="toolbar"声明语义 - 必须配
aria-label(如aria-label="文档编辑工具栏"),只写role不够,WCAG 4.1.2 会报错 - 如果已有可见标题(如
<h2 id="toolbar-title">格式工具</h2>),可用aria-labelledby="toolbar-title"替代aria-label - 禁止嵌套
role="toolbar",也别往里面塞<a href></a>这类导航链接 - 点击按钮前,必须确保编辑容器已聚焦:
editor.focus()不能省,尤其 Safari 和旧 Edge 里不调就静默失败 - 编辑容器得设
tabindex="0",否则键盘无法聚焦,execCommand找不到执行目标 -
document.execCommand('bold', false, null)中第一个参数必须小写,传'Bold'或'BOLD'都不生效 - 空行触发
'insertUnorderedList'会生成孤立<ul></ul>,需提前判断:getSelection().toString().trim() === '' - 移动端 Safari 对
'formatBlock'等命令支持极弱,建议降级为手动插入<p></p>或<h2></h2> - 加粗按钮不该调
execCommand('bold'),而应提取当前选区,包裹**并重置光标位置 - 列表按钮不能依赖
'insertUnorderedList',得手动在光标行前插入-或1. - 所有操作后必须立刻
editor.focus(),否则 iOS Safari 会吞掉下一次输入 - 空行或光标在行首/行尾时要兜底,比如输入
**|**(|是光标)应自动补全为**|**,而非****| - 若真要用
execCommand,只限预览切换或 HTML 导出环节,绝不参与主编辑流 - 监听
document上的selectionchange事件(注意:它不冒泡,挂document才有效) - 用
document.queryCommandState('bold')判断是否已加粗,返回true/false - Firefox 对
'justifyCenter'等对齐命令的queryCommandState支持不稳定,建议 fallback 到getComputedStyle(editor).textAlign - 按钮激活态优先用
aria-pressed="true",比仅切 CSS class 更可靠,也满足可访问性要求
为什么工具栏按钮点了没反应
不是 JS 没绑上,而是上下文断了:编辑区没焦点、选区为空、命令名大小写错,三者占九成原因。
Markdown 编辑器千万别用 execCommand
execCommand 输出 HTML,而 Markdown 工具栏要的是 **text**、- item、[link](url) 这类纯文本结构——二者目标冲突,混用必出光标错位或 DOM 断裂。
如何让按钮实时反映当前格式状态
不能只靠点击更新 UI,得监听选区变化,并用原生 API 查当前样式,否则按钮“按下去了但没亮”。
真正难的不是写按钮,而是让每次点击都精准作用于光标所在词、行或选区;尤其是空行、跨块、移动端失焦这些边界情况,稍不处理就会让用户觉得“这工具栏在跟我作对”。











