/    Sign up×
Community /Pin to ProfileBookmark

[RESOLVED] offsetHeight = zero

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 div to n2 so the span is displayed and likewise onmouseout changes 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;
}[/CODE]

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

[code=html]
<div id=”navbar” class=”navbar” name=”navbar”>
<div id=”n1″ class=”n1″ name=”n1″ onmouseover=”pos(this)” onmouseout=”closeMenu(this)”>
DIV 1-1
<span name=”sub” id=”sub” class=”sub”>
<div id=”n1″ class=”n1″ name=”n1″ onmouseover=”pos(this)” onmouseout=”closeMenu(this)”>
Link 1
<span name=”sub” id=”sub” class=”sub”>
<div id=”n1″ class=”n1″ name=”n1″ onmouseover=”pos(this)” onmouseout=”closeMenu(this)”>Link 1</div>
<div id=”n1″ class=”n1″ name=”n1″ onmouseover=”pos(this)” onmouseout=”closeMenu(this)”>Link 2</div>
<div id=”n1″ class=”n1″ name=”n1″ onmouseover=”pos(this)” onmouseout=”closeMenu(this)”>Link 3</div>
<div id=”n1″ class=”n1″ name=”n1″ onmouseover=”pos(this)” onmouseout=”closeMenu(this)”>Link 4</div>
<div id=”n1″ class=”n1″ name=”n1″ onmouseover=”pos(this)” onmouseout=”closeMenu(this)”>Link 5</div>
<div id=”n1″ class=”n1″ name=”n1″ onmouseover=”pos(this)” onmouseout=”closeMenu(this)”>Link 6</div>
<div id=”n1″ class=”n1″ name=”n1″ onmouseover=”pos(this)” onmouseout=”closeMenu(this)”>Link 7</div>
</span>
</div>

<div id=”n1″ class=”n1″ name=”n1″ onmouseover=”pos(this)” onmouseout=”closeMenu(this)”>Link 2</div>
<div id=”n1″ class=”n1″ name=”n1″ onmouseover=”pos(this)” onmouseout=”closeMenu(this)”>Link 3</div>
<div id=”n1″ class=”n1″ name=”n1″ onmouseover=”pos(this)” onmouseout=”closeMenu(this)”>
Link 4
<span name=”sub” id=”sub” class=”sub”>
<div id=”n1″ class=”n1″ name=”n1″ onmouseover=”pos(this)” onmouseout=”closeMenu(this)”>Link 1</div>
<div id=”n1″ class=”n1″ name=”n1″ onmouseover=”pos(this)” onmouseout=”closeMenu(this)”>Link 2</div>
<div id=”n1″ class=”n1″ name=”n1″ onmouseover=”pos(this)” onmouseout=”closeMenu(this)”>Link 3</div>
<div id=”n1″ class=”n1″ name=”n1″ onmouseover=”pos(this)” onmouseout=”closeMenu(this)”>Link 4</div>
<div id=”n1″ class=”n1″ name=”n1″ onmouseover=”pos(this)” onmouseout=”closeMenu(this)”>Link 5</div>
<div id=”n1″ class=”n1″ name=”n1″ onmouseover=”pos(this)” onmouseout=”closeMenu(this)”>Link 6</div>
<div id=”n1″ class=”n1″ name=”n1″ onmouseover=”pos(this)” onmouseout=”closeMenu(this)”>Link 7</div>
</span>
</div>
<div id=”n1″ class=”n1″ name=”n1″ onmouseover=”pos(this)” onmouseout=”closeMenu(this)”>Link 5</div>
<div id=”n1″ class=”n1″ name=”n1″ onmouseover=”pos(this)” onmouseout=”closeMenu(this)”>Link 6</div>
</span>
</div>
</div>[/code]

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 submenu’s 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);
}
[/CODE]

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?

to post a comment
JavaScript

5 Comments(s)

Copy linkTweet thisAlerts:
@KorApr 03.2007 — The [B]id[/B] must be [COLOR="Red"]unique[/COLOR] on the same document/session... You have a lot of elements with the same id="n1". On the other hand, [I]name[/I] is not allowed to be used for other elements than the form's elements, so far, thus [I]name[/I] for DIV elements is deprecated.
Copy linkTweet thisAlerts:
@spiehauthorApr 03.2007 — So I stripped out all of the Id='n1' and name='n1' etc so the divs only have the className set. The same for the spans removed id=sub and name=sub so they just have className set.

Still it has no effect on the previous problem offsetHeight still being zero when called from a 2nd level deep submenu.
Copy linkTweet thisAlerts:
@spiehauthorApr 06.2007 — So I spent a while reviewing the value of several variables during the mouse events and this is what I've discovered.

This is ALL a bubbling problem for onmouseover and onmouseout. IE has built in mouse events onmouseenter and onmouseleave that do not bubble up and everything works just as intended.

So can anyone explain how I can cancel bubbling for onmouseover and onmouseout for firefox??
Copy linkTweet thisAlerts:
@ricpApr 06.2007 — Two things here, if you need to pick up element sizes when they are not visible on screen, use the visibility property and not display when hiding/showing. That will keep the whitespace.

Secondly the info you seek on FF is:

http://developer.mozilla.org/en/docs/DOM:event.preventDefault

http://developer.mozilla.org/en/docs/DOM:event.stopPropagation
Copy linkTweet thisAlerts:
@spiehauthorApr 12.2007 — I didn't actually need to cancel the event Bubbling. I found these functions and they work perfectly.

[CODE]function containsDOM (container, containee) {
do {
if ((isParent = container == containee))
break;
containee = containee.parentNode;
}
while (containee != null);
return isParent;
}

function checkMouseEnter (evt, element) {
if (element.contains && evt.fromElement) {
return !element.contains(evt.fromElement);
}
else if (evt.relatedTarget) {
return !containsDOM(element, evt.relatedTarget);
}
}

function checkMouseLeave (evt, element) {
if (element.contains && evt.toElement) {
return !element.contains(evt.toElement);
}
else if (evt.relatedTarget) {
return !containsDOM(element, evt.relatedTarget);
}
}[/CODE]
×

Success!

Help @spieh spread the word by sharing this article on Twitter...

Tweet This
Sign in
Forgot password?
Sign in with TwitchSign in with GithubCreate Account
about: ({
version: 0.1.9 BETA 5.4,
whats_new: community page,
up_next: more Davinci•003 tasks,
coming_soon: events calendar,
social: @webDeveloperHQ
});

legal: ({
terms: of use,
privacy: policy
});
changelog: (
version: 0.1.9,
notes: added community page

version: 0.1.8,
notes: added Davinci•003

version: 0.1.7,
notes: upvote answers to bounties

version: 0.1.6,
notes: article editor refresh
)...
recent_tips: (
tipper: @Yussuf4331,
tipped: article
amount: 1000 SATS,

tipper: @darkwebsites540,
tipped: article
amount: 10 SATS,

tipper: @Samric24,
tipped: article
amount: 1000 SATS,
)...