20

I'm having trouble getting the size, in pixels, of a text node using Javascript. Example:

<p>
  first text block
  <b>second text block</b>
</p>

I need to get the bounding box of the two text blocks independently. I could get the size of the second block just by measuring the <b> element, but the first one eludes me. It doesn't appear that textnodes in Javascript have a height or width, so far as I can tell.

Wrapping the first text block in a <span> and measuring that is not an option, because I've discovered that a span does not necessarily inherit all of the styles above it, and when I wrap the text it suddenly changes size. It's like the Heisenberg Uncertainty Principle of Javascript; my attempt to measure something changes it.

I'm building an app that breaks HTML into pages (EPUB HTML, actually), and I need to know the position, height, and width of each block of text on the page so I can know whether to put it on this page or the next page.

Any suggestions?

ccleve
  • 15,239
  • 27
  • 91
  • 157
  • There does appear to be an answer to this. We took a completely different approach to the problem; we're breaking up the pages in the EPUB using multi-column layouts. No text metrics required. – ccleve Aug 05 '11 at 20:55
  • I am wrong. Tim Down has answered it. – ccleve Aug 08 '11 at 22:23

2 Answers2

31

You can do this with a Range that supports CSSOM View extensions, which is most recent browsers (Firefox 4+, WebKit since early 2009, Opera 11, maybe earlier) and a TextRange in IE. The TextRange code is tedious, so I've omitted it here.

jsFiddle: http://jsfiddle.net/gdn6C/1/

Code:

function getTextNodeHeight(textNode) {
    var height = 0;
    if (document.createRange) {
        var range = document.createRange();
        range.selectNodeContents(textNode);
        if (range.getBoundingClientRect) {
            var rect = range.getBoundingClientRect();
            if (rect) {
                height = rect.bottom - rect.top;
            }
        }
    }
    return height;
}
Tim Down
  • 318,141
  • 75
  • 454
  • 536
  • Why would you need to open a special case for IE? The table at http://www.quirksmode.org/dom/w3c_cssom.html suggests that `getBoundingClientRect` is available here too. – Nico Schlömer Mar 06 '15 at 22:04
  • @NicoSchlömer: That page is referring to `getBoundingClientRect` method of elements, not ranges. – Tim Down Mar 07 '15 at 18:29
  • I know this is an old one now but I just tested in IE and it seems to work in IE 11 on Windows 8.1 – John May 14 '15 at 10:03
  • This will not return the precise position of the text in IE11 if there are other nodes in the same line with larger height than the text, like an image. The height will be the line height instead of the selected text height. – Damien Dec 12 '16 at 19:54
0

Try making the elements you wish to measure inline. Inline elements only take up as much space as required. Thus, it has an absolute width and height that can be retrieved by javascript. Block elements fill up the entire width of the containing element. Thus javascript cannot access its width.

Aadit M Shah
  • 72,912
  • 30
  • 168
  • 299