使用jQuery获取元素的实际宽度

20

我正在编写一个用于验证HTML文件“可视正确性”的验证器。其目标是检测元素是否过宽。

这是我的问题的演示。

虚线红线是文档的最大宽度指示器(在本示例中为200px)。第一个段落没有问题,但第二个段落太宽了。尽管如此,以下所有命令仍然返回“200px”作为宽度:

// all return 200, but the value should be larger   
$('#two').width();
$('#two').outerWidth();
$('#two').prop('clientWidth');
请查看Fiddle,以获取更多详细信息。
如何检测这样的超大元素?
更新的问题:更好的提问方式是如何检测超出父元素边界的文本?
更新的要求:不允许更改源HTML或CSS中的任何内容。但我可以使用jQuery对文档进行修改,以便检测那些过宽的元素。

容器本身是200像素,jQuery和调试器都正确报告了。只是文字溢出了。 - Joseph
在控制台中检查指标,#two 的宽度确切为 200px - noob
这是因为你的元素宽度为200像素,而段落正在换行。即使使用 white-space: nowrap;,你仍然会得到200像素的宽度。 - Will Morgan
@Joseph:我想要能够检测出那些溢出。怎么做呢? - Alp
我建议你强制换行它们。 - Joseph
我不被允许更改HTML或CSS代码中的任何内容,请查看我的更新问题。 - Alp
6个回答

14

scrollWidth可以实现:

$("#two").get()[0].scrollWidth 或者 getElementById("two").scrollWidth

这将输出212px,即你所寻找的真实宽度。


2
这个回答应该得到更高的评价。完美地工作,正是所需之物,而不需要修改任何样式。 - Nick Budden
特别适用于包装元素会改变宽度的情况,比如在表格布局中。 - Douwe

14

正如其他人所说,暂时将文本节点包装在内联元素中。

var two = document.getElementById('two'),
    text = two.firstChild,
    wrapper = document.createElement('span');

// wrap it up
wrapper.appendChild(text);
two.appendChild(wrapper);

// better than bad, it's good.
console.log(wrapper.offsetWidth);

// put it back the way it was.
two.removeChild(wrapper);
two.appendChild(text);

这里有一个 getInnerWidth 函数可能会对你有用。将元素传递给它,它将处理包装和取消包装。

http://jsfiddle.net/vv68y/12/

function getInnerWidth(element) {

    var wrapper = document.createElement('span'),
        result;

    while (element.firstChild) {
        wrapper.appendChild(element.firstChild);
    }

    element.appendChild(wrapper);

    result = wrapper.offsetWidth;

    element.removeChild(wrapper);

    while (wrapper.firstChild) {
        element.appendChild(wrapper.firstChild);
    }

    return result;

}

http://jsfiddle.net/vv68y/13/


目前,这个解决方案在我看来似乎是最好的,因为一切都保持不变。您能否制作另一个示例,在当前页面上动态执行相同的所有文本节点的过程? - Alp
@Alp 我觉得这对你没有好处。我会进行更新,请稍等。 - Dagg Nabbit
1
我相信这个答案,因为它提到了The Log,它不仅不差,而且很好! - Suamere

6
这种效果被称为“收缩包裹”,有几种方法可以确定元素的“真实”宽度。

浮动

其中一种方法是浮动您的 <p> 元素,这将强制使其尽可能小,但如果 div 中的任何内容都浮动,则需要使用 clearfix

#two { float: left; }

内联块级元素

插入内联元素应该可以工作。

<p>content</p>

会变成

<p><span>content</span></p>

绝对定位元素

将元素位置改为绝对定位也应该起作用:

#two { position: absolute; }

如果您无法静态更改标记或样式,您可以通过JavaScript动态更改它们。
(绝对定位元素)
var realWidth = $("#two").css("position", "absolute").width();

(浮点数)

var realWidth = $("#two").css("float", "left").width();

(内联块元素)

var t = $("#two").html();
var realWidth = $("#two")
    .empty()
    .append($("<span>").html(t))
    .width();

1

在其中应用word-wrap: break-word;,这样单词就会被分开,不会有任何文本超出容器... 顺便说一下,您无法检查超出容器的文本的宽度。

示例

更新:您可以检查其中文本的宽度是否大于容器的宽度,例如this


我不被允许更改HTML或CSS代码中的任何内容,请查看我的更新问题。 - Alp
@Alp,使用jQuery添加它。$("#two").css("word-wrap", "break-word"); - noob
1
目标是检测缺陷并将结果发送回发布者,以便他可以进行更正,因此我不想让它看起来很好,我只想找出是否 break-word 有任何差异,并在这种情况下发出错误警报。 - Alp

1
正如其他人指出的那样,将元素的 position 改为 absolute 也可以起作用。 这样做会导致内联样式,如果不小心处理可能会影响您的 CSS。以下是消除内联样式的解决方案。
//Change position to absolute
$('#two').css("position", "absolute");
var textWidth = $('#two').width();

//Get rid of the inline style again
$('#two').removeStyle("position");



//Plugin format
(function ($) {
    $.fn.removeStyle = function (style) {
        var search = new RegExp(style + '[^;]+;?', 'g');

        return this.each(function () {
            $(this).attr('style', function (i, style) {
                return style.replace(search, '');
            });
        });
    };
}(jQuery));

0

元素本身被限制在200像素内,但是内部的文本会溢出。如果在P标签中插入一个span(或任何其他内联元素),它就可以正常工作。

http://jsfiddle.net/will/vv68y/5/

希望这能有所帮助 :)

谢谢您的回答,不幸的是我不能更改HTML或CSS源代码。因此,我需要找到一个仅使用jQuery的解决方案。有什么想法吗? - Alp
用jQuery插入span,然后检查宽度怎么样? - will
这可能是有可能的。源代码可能会非常庞大和复杂。我无法想象如何找到所有需要插入跨度的可能位置。 - Alp
1
我认为这可能是你唯一的解决方案。虽然我进行了快速搜索,获取文本节点并以某种方式计算其宽度可能是可能的,但这超出了我的能力范围。无论如何,这是链接。https://dev59.com/xnVC5IYBdhLWcg3wbgdS - will

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接