views:

37

answers:

3

I'm trying to get the height, width, and placement of a section of HTML code, so that I can create a <div> with position: absolute to overlay the HTML in question. Sometimes this HTML is a single element, other times it's a bunch of elements.

I've tried to wrap the HTML code in question in a <span> and then use $('#spanToMeasure').height() and .width() and .offset(), but I'm getting inconsistent results. Sometimes the height and/or width returns as 0, when it really isn't, and sometimes the placement is off.

I've also tried using $(window).load() instead of $(document).ready(), but the results appear the same.

Is my method not working due to CSS that's changing the dimensions/placement? Or is something else going on? Any help is appreciated!

Here's my full code:

  $(document).ready(function() {
    // Create a container to hold all of the overlays.
    var $overlayContainer = $('<div id="easy_edit_overlays">').appendTo('body');

    // Find all of the sections of code to create overlays for.
    $('span.easy_edit').each(function() {
      var $this = $(this);

      $this.removeClass('easy_edit');

      var height = $this.height();
      var width = $this.width();

      var offset = $this.offset();

      // Create overlay.
      var $editOverlay = $('<div>').addClass('easy_edit_overlay')
                                   .height(height)
                                   .width(width)
                                   .css('background-color', 'red')
                                   .css('opacity', '0.5')
                                   .css('top', offset.top)
                                   .css('left', offset.left)
                                   .css('position', 'absolute');

      // Create link to include within overlay.
      var $editLink = $('<a>').attr('href', $this.attr('class'))
                              .attr('target', '_blank')
                              .css('display', 'block')
                              .css('height', height)
                              .css('color', 'red')
                              .text('Edit');

      $editLink.appendTo($editOverlay);

      $editOverlay.appendTo($overlayContainer);

      // Remove the <span> tag and replace with its children.
      $this.replaceWith($this.html());
    });
  });
A: 

That's pretty easily accomplished:

$(document).ready(
    function(){
        $('#elementID').click(
            function(){
                var position = $('#elementID').offset(),
                xPos = position.left,
                yPos = position.top,
                width = $('#elementID').width(); // or $('#element').outerWidth(),
                height = $('#elementID').height();
                $('#x').text('xPos: ' + xPos);
                $('#y').text('yPos: ' + yPos);
                $('#h').text('Height: ' + height);
                $('#w').text('Width: ' + width);
            });
    }
);

Demo at: JS Fiddle

For the inconsistent results, it's worth checking the following:

  1. Whether you're positioning the position: absolute element against the correct container (its parent needs to have a specified position attribute, otherwise it just bubbles up to be positioned against the first ancestor with a specified position).
  2. Whether the elements you're finding the height of exist in the DOM at the time the function is run.
  3. Whether the elements have display: visible.
  4. That the values you're working with in your functions aren't being manipulated by another source elsewhere in your script.
David Thomas
Did you actually read the question? Or look at his code? He's already using everything you've mentioned here.
Ender
@Ender, yes; I did. Hence the edits. I was proving to myself that his code *should* work before I tried to find what the problem(s) might be. Saying it was *pretty easy* does come across as a little crass, though...
David Thomas
@David - Sorry, I was being a little overly hostile there. Thanks for adding more to your answer :)
Ender
@Ender, no worries; I've reacted in much the same way myself sometimes; and, to be fair, I should've posted some suggestions in the original posting of my answer (rather than posted working code and *then* tried to rationalise the problems and editing-in...) =)
David Thomas
+2  A: 

The problem you are having is most likely due to the fact that a <span> is an inline element, which means its dimensions may not be correctly computed. See this article for a description on the way a few attributes apply differently between block and inline elements: http://www.maxdesign.com.au/articles/inline/

As to the positioning, you may want to review the difference between .offset() and .position(). I've linked the documentation for both below:

EDIT:

This doesn't really address the specific problem you're having, but I do have a suggestion to make your life easier. There already exists a plug-in called ternElapse that does exactly what you want to do. Maybe you could use that, instead of re-inventing the wheel?

Hopefully they have already addressed the problem you're tackling and found the solution :)

Ender
Ah, good catch. I hadn't got that far through. +1 =)
David Thomas
Wrapping the code in a `<div>` gives the correct offset now, but I'm still getting heights of 0 in some instances.
Justin Stayton
Are by chance all of the elements floated? That will cause the height to be zero.
Christian Mann
Yes, in fact, it looks like the problematic elements are floated. How can I overcome this?
Justin Stayton
I've added a suggestion for a plug-in to my answer. Hopefully it is helpful :)
Ender
A: 

A span element is an inline element, so it doesn't always cover a square area that can be covered with a div element. It can for example contain two words, and one word is at the end of a line, and the other word is at the beginning of the next line. That would make the span consist of two rectangular areas.

If you want an element that you can always get the size and position of, you should use a block element.

Guffa