JavaScript实现contenteditable div中选中内容字号增大功能遇阻
解决WYSIWYG编辑器「增大字号」按钮统一修改所有选中元素字号的问题
看起来你遇到的问题是因为当前代码把选中区域内的元素当成一个整体,直接用第一个元素的字号覆盖了所有选中元素的样式——这就导致不管原来每个元素的字号差异,操作后全变成一样的了。咱们来一步步修复这个问题:
问题根源分析
你提到的代码里用html.firstValue来获取字号,然后统一设置给所有选中元素,这本质上是忽略了选中区域内每个元素原有的字号值,强制统一成第一个元素的大小,自然会出现所有元素字号相同的问题。
正确的实现思路
我们需要逐个处理选中范围内的每个文本节点/元素,读取它们当前的实际字号,计算增大后的数值,再分别应用样式。这样就能保留每个元素原有的字号差异,只做增量调整。
具体代码实现
下面是基于rangy的完整修复代码,支持对不同字号的选中元素单独增大,同时处理未被span包裹的纯文本节点:
function increaseFontSize() { const selection = rangy.getSelection(); if (selection.isCollapsed) return; // 无选中内容时直接返回 // 遍历每个选中的选区范围 for (let i = 0; i < selection.rangeCount; i++) { const range = selection.getRangeAt(i); // 1. 处理已设置字号的元素(如带style.fontSize的span) const styledNodes = range.getNodes([1], node => { return node.style.fontSize || window.getComputedStyle(node).fontSize !== ''; }); styledNodes.forEach(node => { const computedStyle = window.getComputedStyle(node); const currentFontSize = computedStyle.fontSize; // 提取字号数值和单位(支持pt/px/em等) const sizeValue = parseFloat(currentFontSize); const unit = currentFontSize.replace(/[0-9.]/g, ''); // 这里设置增量:比如每次增加2pt,也可以用比例(sizeValue * 1.2) const newSize = sizeValue + 2; node.style.fontSize = `${newSize}${unit}`; }); // 2. 处理未被包裹的纯文本节点(需要新建span来单独设置字号) const textNodes = range.getNodes([3]); // 3代表文本节点类型 textNodes.forEach(textNode => { const parent = textNode.parentNode; // 如果父元素没有单独设置字号,就给文本节点套一个span if (!parent.style.fontSize) { const span = document.createElement('span'); const parentStyle = window.getComputedStyle(parent); const currentFontSize = parentStyle.fontSize; const sizeValue = parseFloat(currentFontSize); const unit = currentFontSize.replace(/[0-9.]/g, ''); const newSize = sizeValue + 2; span.style.fontSize = `${newSize}${unit}`; // 替换节点:把文本节点放到新span里 parent.replaceChild(span, textNode); span.appendChild(textNode); } }); } // 保持操作后的选区选中状态 selection.setSingleRange(selection.getRangeAt(0)); }
关键细节说明
- 使用
getComputedStyle获取实际字号:有些元素的字号是继承自父元素的,直接读node.style.fontSize可能为空,getComputedStyle能拿到最终生效的样式值。 - 保留原有单位:避免强制转换单位(比如把pt转成px)导致的显示不一致问题。
- 区分处理两种节点:既有已经被span包裹的带样式元素,也有纯文本节点,确保所有选中内容都能正确调整字号。
- 保持选区状态:操作完成后重新设置选区,让用户能继续编辑,提升体验。
内容的提问来源于stack exchange,提问作者Kacper G.




