Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chris Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

offsetHeight returns zero but why?

Status
Not open for further replies.

spieh

Programmer
Apr 3, 2007
2
US
I am making a DHTML menu using css and javascript.

my CSS looks like this. Basically the submenu is conained in a wrapper span that is initially set to display none and onmouseover it changes the class of the parent div to n2 so the span is displayed and likewise onmouseout changes div back to n1 to re-hide the span.

Code:
.navbar {
  float:left;
  position: relative;
  width: 173px;
  background-color:white;
  border: solid 1px black;
  top:200px;
}

.n1 { 
  position:relative;
  background-color: 1b2f3b;
  color: white;
  display:block;
  border-color:black;
  border-width:1px;
  border-style:solid;
  padding: 2px 0px 2px 5px;

}

.n1 span {display:none;}


.n2 {
  position:relative;
  background-color: 095c8e;
  color: white;
  display:block;
  border-style:solid;
  border-width:1px;
  padding: 2px 0px 2px 5px;

}

.n2 span {
  position: absolute;
  top:0px;
  left:150px;
  background-color: 1b2f3b; 
  color: white;
  z-index:1000;
  border-style:solid;
  border-width:2px;
  width:180px;
}

So when I build the html for a sample of the menu it looks like this.

Code:
<div class="navbar">
  <div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">
      DIV 1-1
      <span class="sub">
        <div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">
          Link 1
          <span class="sub">
            <div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 1</div>
            <div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 2</div>
            <div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 3</div>
            <div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 4</div>
            <div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 5</div>
            <div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 6</div>
            <div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 7</div>
          </span>
        </div>
        
        <div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 2</div>
	    <div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 3</div>
	    <div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">
	      Link 4
	      <span class="sub">
            <div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 1</div>
            <div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 2</div>
            <div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 3</div>
            <div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 4</div>
            <div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 5</div>
            <div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 6</div>
            <div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 7</div>
          </span>
	    </div>
	    <div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 5</div>
	    <div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 6</div>
      </span>
    </div>
    <div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">
      DIV 1-2
      <span class="sub">
        <div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">
          Link 1
          <span class="sub">
            <div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 1</div>
            <div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 2</div>
            <div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 3</div>
            <div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 4</div>
            <div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 5</div>
            <div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 6</div>
            <div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 7</div>
          </span>
        </div>
        
        <div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 2</div>
	    <div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 3</div>
	    <div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">
	      Link 4
	      <span class="sub">
            <div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 1</div>
            <div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 2</div>
            <div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 3</div>
            <div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 4</div>
            <div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 5</div>
            <div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 6</div>
            <div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 7</div>
          </span>
	    </div>
	    <div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 5</div>
	    <div class="n1" onmouseover="pos(this)" onmouseout="closeMenu(this)">Link 6</div>
      </span>
    </div>
  </div>
</div>

Changing the class works fine and the menu functions just great except I have the issue of any submenu potentially overflowing the bottom of the window so the user would need to scroll down to see all the options when the menu expands. So I am working on functions to reposition the submenus when they become visible only If they would cause overflow. My javascript looks like this.

Code:
function changeClass(item)
{
  if(item.className == "n1")
    item.className = "n2";
  else if (item.className == "n2")
    item.className = "n1";
}

function getYpos(element)
{
  var y;
  y = element.offsetTop;
  if (element.offsetParent != null)
    y += getYpos(element.offsetParent);
  //alert(y);
  return y;
}

function pos(element)
{
  var y, ch, eh = 0;
    
  changeClass(element);
  
  // get verical position of element in relation to page
  y = getYpos(element);
  
  //element height
  eh = element.offsetHeight;
  
  var cnodes = element.childNodes;
  
  // check to see if element has a submenu (child[1] is the span)
  if (cnodes[1] && cnodes[1].nodeType == 1)
  {
    // get height of submenu
    ch =cnodes[1].offsetHeight;  
  }   
  // checks for submenu overflow and if so, moves submenu up
  if ((y + ch) > document.body.clientHeight)
  {
    ch = ch - eh;
    cnodes[1].style.top = "-" + ch  + "px";
  }
}

function closeMenu(element)
{
  var cnodes = element.childNodes; 
  // reset submenu position to original position
  if (cnodes[1] && cnodes[1].nodeType == 1)
  {
    cnodes[1].style.top = "0px";
  }   
  changeClass(element);
}

This works in both firefox and IE and moves the 1st level submenus up when needed. Now after all this... here is the problem... 2nd level submenus still overflow the bottom of the page and I have done some testing and this is what I found out:

The cnodes[1].offsetHeight is returning the height is zero for all 2nd level submenus during execution. It appears its trying to calculate the height of the hidden span before it's display is set to block. Because it always returns zero the overflow check will always fail and submenus 2 deep will never be moved up. I made sure that I called the changeClass() function so the span would be set to display 'block' prior to calling the offsetHeight but it still returns zero. If i manually set cnodes[1].dispay = block before getting the offsetHeight it correctly gets the height of the submenu but it completely breaks the dhtml effects of the menu.

What doesn't make any sense is, The function works for 1st level deep but nothing deeper than that. And the HTML format for both 1st and 2nd level menus are the same.

Any ideas?
 
I found this is an event bubbling issue. Need to write some code to cancel event bubbling for onmouseover and onmouseout

IE has built in onmouseenter and onmouseleave that do not bubble up.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top