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 strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

CSS Tooltip Z Order with Floated Elements

Status
Not open for further replies.

dismayldream

Programmer
Sep 6, 2007
7
GB
I have a page which contains elements which have all been floated. I also have some javascript which dynamically creates and displays a simple tooltip (code below). However, in Firefox (2.007), the display of the tooltip is flickering (horribly). I've traced this back to the z-index property I provide to the dynamically created <span> element that represents the tooltip. The problem seems to be that the floated elements that are supposed to be below the tooltip are rapidly positioning themselves on top, then below the tooltip, resulting in the flickering. I've tried assinging a z-index value as per: but I'm still having issues. If you uncomment the line
Code:
el.style.zIndex = 10;
in SiteStyle.js, and fire up firefox you'll see what I mean.

If anyone can shed any light on this issue - I'd be most grateful.

Thanks!


SiteStyle.js
Code:
var toolTip = new bomTooltip();

function bomTooltip() 
{
    var timerID;
    
    this.initTooltip = function(text) {
        if(!document.getElementById || !document.getElementsByTagName)
        {  
            return false;
        }
        var el, txtnode;
        el = document.getElementById("cluetip"); 
        if(el == null) 
        {
            el=document.createElement("span");
            el.id="cluetip";
            el.className="cluetiptop";
            el.style.position="absolute";
            el.style.width="170px";
            el.style.height="91px";
            txtnode=document.createElement("span");
            txtnode.style.position="absolute";
            txtnode.style.left="35px";
            txtnode.style.top="23px";
            txtnode.style.width="130px";
            txtnode.style.color="#f00";
            txtnode.style.fontSize="10px";
            if(text) 
            {
                if(text.length > 54)
                {
                    text = text.substr(0, 53) + "...";
                }
            }
            txtnode.appendChild(document.createTextNode(text));
            //txtnode.style.zIndex = 101;
            el.appendChild(txtnode);
            el.style.display="none";
            // the troubling line...
            // el.style.zIndex = 10;
            el.float="left";
            
            
            document.body.appendChild(el);
        }
    } 
    
    this.showTooltip = function(e, inst) {
        var posx=0,posy=0;
        
        if(document.getElementById("cluetip"))
        { 
            document.getElementById("cluetip").style.backgroundImage="";
            document.getElementById("cluetip").style.display="none"; 
        }
        window.clearTimeout(inst.timerID);
        
        if(e == null) 
        {  
            // for IE
            e = window.event;
        }
        if(e.pageX || e.pageY)
        {
            // for Firefox
            posx=e.pageX; 
            posy=e.pageY;
        }
        // for IE
        else if(e.clientX || e.clientY)
        {
            if(document.documentElement.scrollTop)
            {
                posx=e.clientX+document.documentElement.scrollLeft;
                posy=e.clientY+document.documentElement.scrollTop;
            }
            else
            {
                posx=e.clientX+document.body.scrollLeft;
                posy=e.clientY+document.body.scrollTop;
            }
        }
        document.getElementById("cluetip").style.top=(posy-85)+"px";
        document.getElementById("cluetip").style.left=(posx-16)+"px";
        inst.timerID = window.setTimeout(function() { inst.callbackTooltip(); },1000);
    }
 
    this.callbackTooltip = function() {   
        if(document.getElementById("cluetip"))
        {
            document.getElementById("cluetip").style.background="url(images/help.png) no-repeat top";
            document.getElementById("cluetip").style.display="";
        }
        this.timerID == null ? null : window.clearTimeout(this.timerID);
    }
    
    this.hideTooltip = function(e) {
        var tip=document.getElementById("cluetip");
        tip.style.display="none";
        this.timerID == null ? null : window.clearTimeout(this.timerID);
    }
}

testpage.html
Code:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "[URL unfurl="true"]http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">[/URL]

<html>
<head id="Head1"><title>
	Untitled Page
</title><link rel="stylesheet" type="text/css" href="SiteStyle.css" />
    <script type="text/javascript" src="SiteStyle.js"></script>
</head>
<body id="pagebody" style="display:none;" onload="document.getElementById('pagebody').style.display='';toolTip.initTooltip('blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah');">
    <form name="form1" method="post" action="testpage.aspx" id="form1">
<div>
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwULLTE0MDkxNzYwNDNkZL+YyONNI9g2TGoj4txIlY0dgYYn" />
</div>

    <div class="FHFhead">
        <!-- Main toolbar goes here -->
    </div>
    <div class="FHFcontent">
        <h1>
            <span id="ctl00_HeadingLabel">Main Heading</span>
        </h1>
        <div id="ctl00_ValidationSummary1" style="display:none;"></div>
        <div id="ctl00_UpdatePanel1">
            <span id="ctl00_HelperValidator" style="display:none;"></span>
        </div>
        
        <!-- The tabstrip control -->
        <div class="tabview">
            <div class="exhibitreftest" id="ctl00_MainContentPlaceHolder_UpdatePanel10">
                <ul>
                    <li>
                        <h2>Subordinate Heading.</h2>
                    </li>    
                    <li>
                        <span onmouseout="toolTip.hideTooltip();" onmouseover="toolTip.showTooltip(event, toolTip);" onmousemove="toolTip.showTooltip(event, toolTip);">Field 1:</span>
                        <input name="ctl00$MainContentPlaceHolder$BookNumTextBox" type="text" value="33" id="Text1" class="testclass" />
                    </li>
                    <li>
                        <span class="help">Field 2:</span>
                        <input name="ctl00$MainContentPlaceHolder$SealNumTextbox" type="text" value="22" id="ctl00_MainContentPlaceHolder_SealNumTextbox"  />
                    </li>
                </ul>
                <div class="cleardown_spacer"></div> 
            </div>
        </div>
    </div>
</form>
</body>
</html>

SiteStyle.css
Code:
*
{
	font-family: Verdana, Trebuchet, Helvetica, Arial, "MS Sans Serif", Futura;
	cursor: default; 
}

HTML 
{
	BORDER-RIGHT: 0px; /* remove borders */
	PADDING-RIGHT: 0px; 
	BORDER-TOP: 0px; 
	PADDING-LEFT: 0px; /*remove padding */
	PADDING-BOTTOM: 0px; 
	MARGIN: 0px; /* remove margins */
	OVERFLOW: hidden; /*get rid of scroll bars in IE */
	BORDER-LEFT: 0px; 
	PADDING-TOP: 0px; 
	BORDER-BOTTOM: 0px; 
	HEIGHT: 100%; /* fix height to 100% for IE */
	max-height: 100%; /* fix height for other browsers */
    FONT-SIZE: 12px; /*.8em;*/
    border-collapse: collapse;
	
}

BODY {
	BORDER-RIGHT: 0px; 
	PADDING-RIGHT: 0px; 
	BORDER-TOP: 0px; /* remove borders */
	PADDING-LEFT: 0px; /*remove padding */
	PADDING-BOTTOM: 0px; 
	MARGIN: 0px;  /* remove margins */
	OVERFLOW: hidden; /*get rid of scroll bars in IE */
	BORDER-LEFT: 0px; 
	PADDING-TOP: 0px; 
	BORDER-BOTTOM: 0px; 
	HEIGHT: 100%;  /* fix height to 100% for IE */
	max-height: 100%; /* fix height for other browsers */
    FONT-FAMILY: Verdana, Trebuchet, Helvetica, Arial, "MS Sans Serif", Futura;
    FONT-SIZE: 12px; /*.8em;*/
    FONT-WEIGHT: normal;
    LETTER-SPACING: normal;
    TEXT-TRANSFORM: none;
    WORD-SPACING: normal;
}

.FHFhead 
{
	position:absolute; 
	top:0; 
	height:32px; 
	z-index:5;
	overflow: hidden;
	
}

.FHFcontent 
{
	Z-INDEX: 3;  /* If required to cover any other divs */
	RIGHT: 0px; /* this will put the scroll bar at the right of the page */
	LEFT: 00px; /* a value to miss any navigation div */
	OVERFLOW: auto; /* add scroll bars as necessary */
	BOTTOM: 21px; /* a value to miss the footer */
	POSITION: absolute; /* position absolutely */
	TOP: 32px; /* a value to miss the header */
    FONT-SIZE: 12px; /*.8em;*/
	
}

/* One of the above?*/

div
{
	/* Debug only */
	/*border: solid 1px red; */
	line-height: 20px;
	width: 100%;
}

div.FHFcontent 
{
	text-align: left;
	margin-left: 50px;
}

div.tabview ul
{
	list-style: none none inside;
	margin:0;
	padding:0;
}

div.tabview li
{
	clear: both;	
}

div.tabview span, div.tabview label
{
	float: left;
	text-align: left;
	width: 150px;
	border: solid 1px #edf2ec;
	border-collapse: collapse;
	background-color: #fbfbfb;
	vertical-align: middle;
	padding-left: 5px;
	padding-right: 5px;
}

div.tabview label
{
	width: 250px;
}

div.tabview span.myclass
{
	text-decoration: none;
}

select,option,textarea
{
	float: left;
	border: solid 1px #edf2ec;
	border-collapse: collapse;
	vertical-align: middle;
}

input
{
	float:left;
	height: 18px;
	vertical-align: middle;
}

input[type="checkbox"], input[type="text"]
{
	border: solid 1px #edf2ec;
	border-collapse: collapse;
}

input[type="text"]
{
	padding-left: 5px;
	width: 155px;
	cursor: text;	
}

input[type="checkbox"] 
{
	height: 22px;
}

input[type="submit"]
{
	width: 100px; 
	height: 22px;
	background: white url(images/gradient.png) repeat-x;
	padding: 0;
	margin: 0;
	font-size: 12px;
}

h2
{
	float: left;
	margin: 0;
	padding: 10px 0 10px 0;
	font-size: 23px;
	font-weight: bold;
}

h1
{
	font-size: 28px;
	font-weight: bold;
}

.cleardown_spacer
{
	clear: both;
	display: none;
}


#tabnav
{
	margin: 0;
	padding: 0; 
	float: none;
	clear: both;
}

#tabnav > li
{
	padding: 0px 5px 5px 5px;
	border: solid 1px #edf2ec;
	background: white url(images/gradient.png) repeat-x;
	list-style: none none outside;
	float:left;
	border-bottom: none;
	height: 15px;
	font-size: 11px;
}

#tabnav > li:hover
{
	background: #f4c00f;
	cursor: pointer;
}

#tabnav + br + div
{
	border-top: solid 1px #edf2ec;
}
 
For any that are interested - I resolved the issue. It turns out to be a cyclical firing of the onmousemove, onmouseover event in firefox. The fix was to wire in event listeners, and determine if the mouse pointer was over the element raising the tooltip. The working code (with comments) is below:

SiteStyle.js
Code:
/* Provides a custom cross-browser (IE7/Firefox 2) tooltip that will display above any
   DOM element. To use; wire the following events to the element(s) that will display a tooltip:

   onmouseout="clueTip.hideTooltip(event, this, tipInstance);" 
   onmouseover="clueTip.showTooltip(event, tipInstance);" 
   onmousemove="clueTip.showTooltip(event, tipInstance);"
   
   Note: tipInstance should be declared in the <head> of the page as a global instance: 
   
   <script type="text/javascript">
        var tipInstance = new bomTooltip();
   </script>
   
   Other parameters should be passed verbatim. */
function bomTooltip() 
{
    var timerID;
    
    /* Initializes the tooltip along with any background image and default text. Also provides
       event listening to intercept any events raised by the tooltip or it's children. */
    this.initTooltip = function(text, inst) {
        if(!document.getElementById || !document.getElementsByTagName)
        {  
            return false;
        }
        var el, txtnode;
        el = document.getElementById("cluetip"); 
        if(el == null) 
        {
            el=document.createElement("span");
            el.id="cluetip";
            el.className="cluetiptop";
            el.style.position="absolute";
            el.style.width="170px";
            el.style.height="91px";
            txtnode=document.createElement("span");
            txtnode.style.position="absolute";
            txtnode.style.left="35px";
            txtnode.style.top="23px";
            txtnode.style.width="130px";
            txtnode.style.color="#f00";
            txtnode.style.fontSize="10px";
            
            // Trim any default string to a reasonable size, and append to the text span.
            if(text) {if(text.length > 54) {text = text.substr(0, 53) + "...";}}
            txtnode.appendChild(document.createTextNode(text));  

            el.appendChild(txtnode);
            el.style.display="none";
            // The zIndex value must be the highest in the raising element's context. 
            // See: [URL unfurl="true"]http://css-discuss.incutio.com/?page=OverlappingAndZIndex[/URL] for more information.
            el.style.zIndex = 10;
            el.float="left";
            
            // Add the tooltip directly to the document body.
            document.body.appendChild(el);
            
            // Because the tooltip element is bound directly to the <body> element of the DOM 
            // document, any events propogated by the tooltip will bubble to the <body> rather then 
            // the element that raised the tooltip. Event capturing ensures that any motion of the 
            // mouse is intercepted and correctly handled whether it occurs on the raising element or
            // on the tooltip. 
            if(el.addEventListener)
            {
                // for Firefox
                el.addEventListener("click",inst.hideTooltipElement, true);
                el.addEventListener("mousemove",inst.hideTooltipElement, true);
            }
            else if(el.attachEvent) 
            {
                // for IE
                el.attachEvent("onclick",inst.hideTooltipElement);
                el.attachEvent("onmousemove", inst.hideTooltipElement);
            }
        }
    } 
    
    /* Fired whenever the tooltip is required for display. Typically this method will be called
       from the raising element's onmouseover() and onmousemove() events. */
    this.showTooltip = function(e, inst) {
        var posx=0,posy=0;  // Cursor position relative to the documents top left. 
                
        if(document.getElementById("cluetip"))
        { 
            document.getElementById("cluetip").style.backgroundImage="";
            document.getElementById("cluetip").style.display="none"; 
        }
        window.clearTimeout(inst.timerID);
        
        if(e == null) 
        {  
            // for IE
            e = window.event;
        }
        if(e.pageX || e.pageY)
        {
            // for Firefox
            posx=e.pageX; 
            posy=e.pageY;
        }
        // for IE
        else if(e.clientX || e.clientY)
        {
            if(document.documentElement.scrollTop)
            {
                posx=e.clientX+document.documentElement.scrollLeft;
                posy=e.clientY+document.documentElement.scrollTop;
            }
            else
            {
                posx=e.clientX+document.body.scrollLeft;
                posy=e.clientY+document.body.scrollTop;
            }
        }
        document.getElementById("cluetip").style.top=(posy-85)+"px";
        document.getElementById("cluetip").style.left=(posx-16)+"px";
        inst.timerID = window.setTimeout(function() { inst.callbackTooltip(); },1000);
    }
 
    /* Raised when the tooltip is required for display. The time before this callBack is raised is
       determined in the call to showTooltip(). */
    this.callbackTooltip = function() {   
        if(document.getElementById("cluetip"))
        {
            document.getElementById("cluetip").style.background="url(images/help.png) no-repeat top";
            document.getElementById("cluetip").style.display="";
        }
        this.timerID == null ? null : window.clearTimeout(this.timerID);
    }
    
    /* Checks to determine if the mouse pointer exists within the element that raised it.
       If it does, the tooltip remains displayed, otherwise it is hidden (call to hideTooltipElement()).
       Takes three arguments, the event, the element that raised the tooltip and an instance of the 
       bomTooltip class. */
    this.hideTooltip = function(e, handler, inst) {
        if(e.pageX || e.pageY)
        {
            // Locate the elements absolute position on the document
            var pos = inst.findPos(handler);
            
            // Determine if the mouse pointer is within the element that raised the tooltip. 
            // If it *is not* within the element, hide the tooltip.
            if(!((e.pageX <= (pos[0] + handler.offsetWidth)) && (e.pageX >= pos[0])) &&
                ((e.pageY <= (pos[1] + handler.offsetHeight)) && (e.pageY >= pos[1])))
            {
                inst.hideTooltipElement();
            }
        }
        else
        {
            // IE 7 does not suffer from cyclical firing of onmousemove(), onmouseout() events
            // so the tooltip can be immediatley hidden.
            inst.hideTooltipElement();
        }
        this.timerID == null ? null : window.clearTimeout(this.timerID);
    }
    
    /* Performs CSS manipulation that hides the actual tooltip element. */
    this.hideTooltipElement = function(){
        document.getElementById("cluetip").style.display="none";
    }
    
    /* Locates the current position of the supplied element (obj) in relation to the <html> (root)
       element's top and left. */ 
    this.findPos = function(obj) {
	    var curleft = curtop = 0;
	    if (obj.offsetParent) 
	    {
		    curleft = obj.offsetLeft;
		    curtop = obj.offsetTop;
		    while (obj = obj.offsetParent) 
		    {
			    curleft += obj.offsetLeft;
			    curtop += obj.offsetTop;
		    }
	    }
	    return [curleft,curtop];
    }
}
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top