Suppose I have a page element (DIV, SPAN whatever) and want to retrieve the position and width/height of it. What is the best way?

for x/y i have this:

function getElementPos (el) {
    var curleft = curtop = 0;
    if (!el.offsetParent) {
        alert("Your browser does not support a necessary feature.  Please upgrade to a newer browser");
        return;
    }
    curleft = obj.offsetLeft
    curtop = obj.offsetTop
    while (obj = obj.offsetParent) {
        curleft += obj.offsetLeft
        curtop += obj.offsetTop
    }
    return {left:curleft, top:curtop};
}

For width/height I am familiar with element.style.width but am wondering how reliable that is across all browsers. and whether it works if no style or class has been defined for an element.

    The style.width value would probably be problematic, depending on exactly what you want to do with it. In particular, table cells may exceed it if there is some word or image that forces the cell to "stretch" to contain it. Also, if it matters, it would only apply to block-level elements. Lastly, the actual displayed width will vary between CSS standards-compliant browsers and IE in "quirks mode", as the standards width is the style.width value + left margin + left border + left margin + right padding + right border + right margin, whereas IE in "quirks mode" applies the width to the entire element (and then the margins and such subtract from the actual content area).

      There are (supposed to be) element.clientWidth/clientHeight - I haven't done a survey on their level of support. Whether it counts padding etc. or not is another question.

        document.getElementById('blah').offsetHeight (offsetWidth)
        would be your best choice, but they are only available after the page renders. so JS executed before the <body> tag loads would lack that, since document.getElementBy wont work

          Rulian, you nailed it I think. That's working quite well for me. I was making a 'click shield' for some Javascript components to prevent obsessive users from clicking them while they're busy dealing with AJAX calls. It's basically a DIV that hovers in front of the component. At first it seemed like offsetWidth/Height failed to account for the padding/margin/borders but then I realized that I had altered the class of the DIV after displaying my click shield.

          Weedpacket, I did find the need to use clientHeight for the x/y click of a mouse. Apparently the x and y params returned by a mouseclick event are not particularly useful for positioning contextmenus or other object. Thanks to the wonderful quirksmode for the inspiration behind this bit of code.

          /**
           * Returns the mouse position from an event
           * @param Event e The mouse-related event
           * @return Object An object with x and y properties
           */
          function getPos(evt) {
          	var posx = 0;
          	var posy = 0;
          	if (evt.pageX || evt.pageY) 	{
          		posx = evt.pageX;
          		posy = evt.pageY;
          	}
          	else if (evt.clientX || evt.clientY) 	{
          		posx = evt.clientX + document.body.scrollLeft
          			+ document.documentElement.scrollLeft;
          		posy = evt.clientY + document.body.scrollTop
          			+ document.documentElement.scrollTop;
          	}
          	return {x:posx, y:posy};
          }
          

          Nog, you are right about the weirdness of layout being a severe complication in this mess. I have started to use only STRICT doctypes which helps (but NOT if you've designed your entire page for TRANSITIONAL - DO NOT SWITCH). I also seem to have learned that any htmlElement.style.propertyName only contains a value if 'propertyName' has been explicitly applied by giving the element itself using a style attribute. You can't retrieve any style properties inherited from a class or parent or anything.

            sneakyimp wrote:

            I was making a 'click shield' for some Javascript components to prevent obsessive users from clicking them while they're busy dealing with AJAX calls.

            An alternative would be to have the handler check. When the call starts, set a property to true, and set it to false on completion. When the event fires, the handler checks the property and only proceeds if the property is false.

              Write a Reply...