20

I am writing a validator for "visual correctness" of html files. The goal is to detect too wide elements.

Here is a demo of my problem.

The dotted red line is an indicator of the max width of the document (200px in this example). The first paragraph is fine, but the second is too wide. Nevertheless, all of the following commands still return "200px" as the width:

// all return 200, but the value should be larger   
$('#two').width();
$('#two').outerWidth();
$('#two').prop('clientWidth');

Please see the Fiddle for more details.

How can i detect such oversized elements?

Updated question: Better to ask, how can i detect text that exceeds the borders of their parent elements?

Updated requirement: I am not allowed to change anything in the source HTML or CSS. But i can do anything i want with jQuery to modify the document, so that i can detect those too wide elements.

Alp
  • 29,274
  • 27
  • 120
  • 198

6 Answers6

14

As others have said, temporarily wrap the text node in an inline element.

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);

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

Here is a getInnerWidth function that should be useful to you. Pass it an element and it will handle the wrapping and unwrapping.

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/

Dagg Nabbit
  • 75,346
  • 19
  • 113
  • 141
  • currently, this solution looks like the best one to me, because everything remains as it was before. can you make another example which is dynamically doing the same procedure for all text nodes on the current page? – Alp Apr 23 '12 at 12:45
  • @Alp I don't think it would do you any good. I'll make an update, hang on. – Dagg Nabbit Apr 23 '12 at 13:38
  • 1
    I trust this answer because of the reference to [The Log](https://www.youtube.com/watch?v=-fQGPZTECYs), It's better than bad, it's good! – Suamere Aug 16 '17 at 20:43
14

scrollWidth will do it:

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

this outputs 212px, the real width you are looking for.

NateQ
  • 781
  • 9
  • 13
  • 2
    This answer should be more highly rated. Works perfectly, exactly what's needed, without modifying any styles. – Nick Budden Aug 27 '16 at 14:52
  • Especially useful when wrapping the element will alter the width, like in a table layout – Douwe May 03 '18 at 15:32
6

This effect is called "shrinkwrapping", and there's a couple of ways to determine the "real" width of the element.

Float

One of the ways that you can use is to float your <p> element which will force it as small as possible, but you'll need to use a clearfix if anything inside your div is floating:

#two { float: left; }

Inline-block element

Inserting an inline element should work.

<p>content</p>

would become

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

Absolutely positioned element

Changing the element position to be absolute should also work:

#two { position: absolute; }

If you can't statically change the markup or the style, you can always change them dynamically through JavaScript.

(absolutely positioned element)

var realWidth = $("#two").css("position", "absolute").width();

(float)

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

(inline-block element)

var t = $("#two").html();
var realWidth = $("#two")
    .empty()
    .append($("<span>").html(t))
    .width();
noob
  • 8,982
  • 4
  • 37
  • 65
Alon Gubkin
  • 56,458
  • 54
  • 195
  • 288
1

Apply word-wrap: break-word; to it.. so the word will break and there won't be any text going out of the container... btw you can't check the width of the text which is going out of the container.

Example

Update: You can check if the width of text in it is bigger than the width of the container like this

noob
  • 8,982
  • 4
  • 37
  • 65
  • i am not allowed to change anything in the html or css code, see my updated question – Alp Apr 23 '12 at 08:52
  • @Alp so add it with jQuery. `$("#two").css("word-wrap", "break-word");` – noob Apr 23 '12 at 08:53
  • 1
    the goal is not to modify the code, but to detect flaws and send a result back to the publisher so that he can correct it. so i do not want to let it look fine, i just want to find out if break-word does any difference and alert an error if that's the case – Alp Apr 23 '12 at 08:55
1

As others have pointed out, changing the position of the element to absolute also works. Doing this will result in an inline-style which can mess with your css afterwards if you don't watch out. Here is a solution to get rid of the inline style again.

//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));
Sebbas
  • 399
  • 4
  • 12
0

The element itself is constrained to 200px, but the text inside spills out. If you insert a span (or any other inline element) inside the P tag it works fine.

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

Hope that helps :)

will
  • 4,557
  • 6
  • 32
  • 33
  • thanks for you answer, unfortunately i am not allowed to change anything in the html or css source. so i need to find a jquery only solution. any ideas? – Alp Apr 23 '12 at 08:51
  • How about inserting the span with jquery and then checking the width? – will Apr 23 '12 at 08:52
  • That could be a possibility. The source can be quite big and complex. I cannot image a way to find all possible locations where i have to insert spans. – Alp Apr 23 '12 at 08:54
  • 1
    I think it may be your only solution. I did a quick search though and getting the text node and somehow calculating the width of that may be possible, but it's beyond me. Here's the link anyway. http://stackoverflow.com/questions/298750/how-do-i-select-text-nodes-with-jquery – will Apr 23 '12 at 09:03