javascript - 为什么选择范围的边框比实际选择的文本宽?

标签 javascript css layout bounding-box

我需要获取文本选择的边界矩形。我正在使用这段代码:

    if (window.getSelection && window.getSelection().rangeCount) {
      var range = window.getSelection().getRangeAt(0).cloneRange()
      if (range.getBoundingClientRect && range.getBoundingClientRect()!=null)
        return range.getBoundingClientRect()
    }

但它通常会返回一个比文本选择宽得多的矩形,即使所选文本的每个元素都没有延伸那么宽。

例如,当我选择 https://simple.wikipedia.org/wiki/Gluon 的前两段文本时矩形包含右侧的图片。

似乎每次当段落边界位于文本选择内部时都会出现此问题,这会使矩形扩展到段落宽度。

如何解决这个问题?

最佳答案

多段落选择中包含的图像可能会对您想要完成的任务或您想要解释文档结构的方式产生问题 - 但从 HTML 的 Angular 来看,这并不是“错误”/CSS 布局模型或浏览器的布局引擎。

简化文档结构:

<div id="nw-content-text">
    <div style="float: right">
        <img src="gluons.png">
    </div>
    <p>From Wikipedia...</p>
    <p>Gluons are what hold quarks together...</p>
    ...
</div>

例如,在 Chrome 中,检查页面。然后在元素 View 中选择 <p> 之一标签。渲染 View 将显示突出显示的背景,延伸到整个图像区域:

show para image overlap

这是因为向右浮动的图像确实消耗了段落最大可能边界框的一部分。如果您只想考虑段落文本,那感觉不对,但这就是 CSS 布局模型的工作原理。根据您的字体大小等,您可以选择第三段,因为它在图像下方流动,并且它确实流动到相同的最右边缘。

鉴于 float: right图像的容器,浏览器“认为”图像及其容器 <div> s“lives”位于第一段右侧,第二段之前。这就是它的逻辑“附着点”或“ anchor ”。选择第一段,浏览器就知道不包含图像。选择第二个,同样。不过,选择组合后,图像会正确包含在内,因为 anchor 位于两个段落之间。单独询问任一段落的边界框,浏览器会用一个紧密的框进行响应。但是要求跨越这些段落的选择范围,并且它必须包括 anchor 和 anchor 代表的包含图像。包括图像在内的更大的边界框是正确的答案。

好了,布局理论就解释了为什么会发生这种情况。现在如何让它执行您希望它执行的操作,并从选择边界框中排除包含的图像?

鉴于 CSS 和浏览器无法按照您想要的方式解释选择,您将无法使用 getBoundingClientRect()直接在选择上。但是,您可以从选择导航到包含的节点,并过滤掉您不需要的任何标签。在这种情况下,您似乎只想要 <p>标签,很容易过滤。计算选择中每个段落的边界框,然后返回一个作为它们并集的框。

请注意,使用范围有点棘手,特别是因为浏览器历史上有不同的模型来管理它们。像 rangy 这样的跨浏览器库可能会有所帮助,尽管简单地从范围导航到底层节点可能不需要那么多额外的框架。 Stack Overflow 上有很多关于“从 JavaScript 选择到底层节点”的文章,其中包含许多代码示例。它们并不都是简单的......但只是过滤 paras 是一个相当简单的情况。或者,如果您不想深入研究所有范围问题,您可以使用类似 Selection.containsNode() 的内容。不太优雅但仍然快速迭代可能的节点并查看它们是否在选择中。

另请注意:您的示例文档只需过滤 paras,并且只需要排除一个 float 元素,就可以使事情变得简单。但所有 HTML/CSS 文档的可变性巨大。这种可变性会使解决方案变得脆弱。例如。如果有时您需要过滤的不仅仅是 <p>元素,或者需要过滤到不属于紧密包装标签的文本节点中间,事情很快就会变得更加危险。这些变化和不同的边缘情况将使您对选择的边界框应包含(并应忽略)的内容的重新解释变得复杂。

关于javascript - 为什么选择范围的边框比实际选择的文本宽?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38968252/

相关文章:

javascript - jQuery 下拉菜单实现

jquery - 如何更改最后一个单词出现在面包屑中的颜色

html - 将文本与字形对齐

仅在 Chrome 和 Safari 中存在 CSS 边距问题

javascript - jQuery 获取 <div> 标签之间的内容

javascript - Winston 记录器将 "undefined"附加到每个日志条目

javascript - 使用 Javascript 在文本框中只允许数值

html - :hover not working

html - 是否可以让网络浏览器滚动以显示网络浏览器视口(viewport)之外的 CSS 固定位置元素?

android - 如何在相对布局中居中表格布局