This article describes how the tooltips are implemented on this Web site. The browser-generated tooltips are described and a method of generating them with CSS-only was developed. This method tended to clip the tooltip when the link was next to an edge of the page so that a DHTML-based method was developed. This last method is now used throughout the site.
When you surf on the Web, you like to have informative clues on the page that you read. On the Web, such popup responsive hints are called "tooltips" which is one name given to the small box that appears when you hover over an object on your screen.
Browser-based tooltips
Displaying tooltips is a very easy task in HTML. Just use the "title" attribute. Most modern browsers support titles on elements like images and links by displaying tooltips. If you hover your mouse over a link that includes a title, the title will display in a small box next to the mouse as shown here.
This is quite helpful, but the display of the title attribute is in the hands of the browser, and they all have different ideas about how to handle them, particularly when the text is long enough to need more than one line. Other than depending on browsers' displays, there seems to be no author accessible mechanism to style these attribute-based "tooltips" [Community MX].
Producing tooltips with CSS
Cascading style sheets provide an alternative way of displaying tooltips. Although any tag could be used for tooltips, because of the erratic rendering of Internet Explorer, the generation of tooltips is limited to the <a> tag only. This tag is the anchor tag: it is marked text that is the start and/or destination of a hypertext link. It accepts several attributes, but either the NAME (the anchor is the target) or HREF (the anchor is a destination) attribute is required.
Here is how I have proceeded: tooltips are implemented as follows. In the tags, the <em>Here I use the <em> tag to insert the text of the tooltip. Most people use the <span> tag but I prefer <em> since I very seldom use it in this context tag delimits the text that will be displayed in the tooltip. This way of implementing the tooltips is very common on the web. On this web site, there are two types of tooltip-enabled anchor tags:
- standard hyperlink - The tooltips for the <a> tags
provide extra information on selected links in the text of a page. Here is a link exampleThis is a pure-CSS "standard" tooltip-enabled link generator generated by the code that follows:
<a href="http://www.gtro.com/web/tooltips_e.php">link example <em>This is a "standard" tooltip-enabled link</em> </a>
- pseudo hyperlink - These hyperlinks are called "pseudo" because the hyperlink does not react if clicked. When hovered, these links generate a tooltip. The <a> tags with class "tooltip" provide extra information for selected words in the text of a page. The CSS statements of the class replace the standard <a> style by another style as shown in this exampleThis is a pure-CSS "pseudo" tooltip-enabled link. It is generated by the code that follows:
<e href="javascript:void(0)" class="tooltip">example
<em>This is a "pseudo" tooltip-enabled link</em>
</em>
where javascript:void(0) prevents the browser from loading a new page (or refreshing the current page) if the hovered item is clicked.
In both cases, the object inside the <a> tag become tooltip-enabled and create a tooltip displaying the object located within their <em> tag.
Except for the fact that the tooltip may be clipped on certain occasions, the rendering of the tooltips is adequate on the browsers on which I have tested them (Internet Explorer 8.0, Chrome, Netscape Navigator 9.0, Opera and Safari 5.0) but clipping remains a problem..
A DHTML solution to clipping
With pure CSS-based tooltips, clipping of the tooltip when the link was located next to a border of the page was an annoyance and there is nothing that CSS can do about it. That is why I undertook a survey of the Web for a DHTML solution.
Strictly speaking, DHTML uses JavaScript to modify the CSS styles of HTML elements [based on DHTML]. This requires parts of the page to move or appear/disappear. This can be done reliably using the <div> element and in many cases the <span> element, when they are positioned using the position: absolute; or position: relative; style (except when changing the display style).
During the search on the Web, I found a number of potential solutions but the one described in the article entitled "Extended Tooltips" by Stephen Chapman, Felgall Pty Ltd, published on About.com looked promising althougt its requirement for a distinctive "id" attribute for each link was repulsive.
My first idea was to use no "id" attribute and use the event generated to get a handle on the anchor element that triggered it (see Annex) and from this handle, fetch its inner <em> element that contains the text of the tooltip and display it. It worked but remained somewhat unstable and produced occasional Javascript errors. I gave up.
Since I could not correct the problem without using "id" attributes, I considered that having only one "id" would be the next best solution. I tought of defining a unique "tooltipholder" <div>-element located early in the <body> of the page where the tooltip text would be inserted dynamically when any of the tooltip-enabled links are hovered over. This works as follows. Let's define the tooltipholder <div> as follows
<div id="model"></div>
give it the "id" model (the only "id" used) and position it early in the <body> of the page. Since it is empty, it won't display. Now, let's define the pseudo-hyperlink as follows:
<a href="#" class="tooltip"
onMouseOut="showtooltip(event)"
onMouseOver="showtooltip(event, 'This is the text of a DHTML-enabled tooltip.')"
onClick="return false">
This is a tooltip-enabled pseudo-hyperlink
</a>
;
The <a> tag reacts to three events: onMouseOver, onMouseOut and onClick. On the first two events, the Javascript function showtooltip() is called with two arguments for the "onMouseOver" event and only one for the "onMouseOut" event. The second argument of showtooltip() is the text of the tooltip.
It is generated by the Javascript code that follows:
function showtooltip(evt, text)
{
if (document.getElementById)
{
pageWidth = window.innerWidth
|| document.documentElement.clientWidth
|| document.body.clientWidth;
node = document.getElementById('model');
node.innerHTML = text; // transfer the text of the tooltip to the placeholderr
// get its style sheet
nodeVisibility = nodeStyle.visibility; // fetch the "visibility attribute
if (nodeVisibility == "visible" || nodeVisibility == "show")
nodeStyle.visibility = "hidden";
else // nodeVisibility was "hidden"
{
if (node.offsetWidth) // calculation of the tooltip Width
tooltipWidth = node.offsetWidth;
else if (node.clip.width)
tooltipWidth = node.clip.width; // width generated by the browser
xCursorPosition = mouseX(evt) - tooltipWidth/2;
yCursorPosition = mouseY(evt) + 20;
if (xCursorPosition < 2) xCursorPosition = 2; // avoid clipping left
rightOverlap = xCursorPosition + tooltipWidth - pageWidth;
if (rightOverlap > 0) xCursorPosition -= rightOverlap + 20; // avoid clipping right
nodeStyle.left = xCursorPosition + 'px'; // set "left" in CSS
nodeStyle.top = yCursorPosition + 'px'; // set "top" in CSS
nodeStyle.visibility = "visible"; // show tooltip
}
}
}
What does this code do?
- It fetches the page width from the browser (variable pageWidth);
- It ontains a handle on the tooltipholder <div> element with id="model";
- It fills the tooltipholder with the text of the tooltip (the 2nd argument of the function)
- It queries its the style sheet for its visibility;
- Then, it take one of two routes: if the visibility attribute is "hidden", it built the tooltip and display it or hide it if the visibility attribute is otherwise;
- In the first instance, it compute the coordinates of the display: it is going to be a rectangle that will occupy an area on the screen. The program fetches the "offsetWidth" property which tell the program how much horizontal space the browser will use to display the tooltip (in pixels);
- The rest is the execution of an algorithm which does its best to avoid clipping.
- Finally, it makes the tooltip visible.
The CSS for these tooltips is as follows:
#model
{
position: absolute;
z-index: 100
visibility: hidden
color: <?php echo $Colors[0] ?>;
background: <?php echo $Colors[2] ?>;
border: 2px solid <?php echo $Colors[0] ?>;
-moz-border-radius: 15px;
-webkit-border-radius: 15px;
border-radius: 15px;
padding: 5px;
color: <?php echo $Colors[0] ?>;
font-size: 12pt;
font-weight: normal;
font-style: normal;
}
It was not a bad solution but my discorery of jQuery made it obsolete.
A jQuery solution
jQuery is a fast and concise JavaScript Library that simplifies HTML document traversing, event handling, animating, and Ajax interactions for rapid web development. jQuery is designed to change the way that you write JavaScript [jQuery]. It is a cross-browser JavaScript library designed to simplify the client-side scripting of HTML. It was released in January 2006 at BarCamp NYC by John Resig and it is used by over 41% of the 10,000 most visited websites, jQuery is the most popular JavaScript library in use today.
The basic philosophy in jQuery is to select a set of DOM elements, and do something to them. To this end, jQuery has a powerful selection mechanism making use of CSS and special syntax. The starting point of the framework is the magical $, which is an alias for the jQuery class. JavaScript doesn't reserve the $ for anything so it can be used as a variable or type name. Everything is accomplished by constructing a jQuery object and giving it some arguments.
With the discovery of this library, I have built a very simple tooltip generator with the very few lines of code that follow:
$('a.trigger').mouseover(function(e) // OnMouseOver event
{
// create the tooltip holder
$(this).append('<div id="tooltip">' + $(this).attr('title') + '</div>');
$(this).attr('title',''); // defeat default browser reaction
$('#tooltip').show(); // show the tooltip
}).mousemove(function(e) // OnMouse mode event
{
$('#tooltip').css('top', e.pageY + 20 ); // tooltip 20px below mouse poiunter
$('#tooltip').css('left', e.pageX); // tooltip with mouse pointer
}).mouseout(function() // OnMouseOut event
{
$(this).attr('title',$('#tooltip').html()); // set the title back to initial value
$(this).children('div#tooltip').remove(); // get rid of the tooltip holder
});
In the code, the events that the script reacts to are highlighted in yellow. On the OnMouseOver event, a tooltip holder is created on the fly and the text of the "title" attribute of the anchor is assigned to it. After having cleared the "title" attribute of the anchor in order to defeat the standard browser reaction, the tooltip is displayed. The OnMouseMove event keeps the tooltip next to the mouse pointer and the OnMouseOut event reassign its value to the "title" attribute of the anchor and destroy the tooltip holder. The result is quite impressive as you can see if you hover this text. It is produced by the following anchor statement:
<a class="trigger" title="This is the text of a jQuery tooltip")>
if you hover this text
</a>
and that's all!
$(document).ready(function() // wait for the DOM to load
{
$('a.trigger').mouseover(function(e) // OnMouseOver event
{
$(this).append('<div id="tooltip">' + $(this).attr('title') + '</div>'); // create the tooltip container
$(this).attr('title',''); // empty the title attribute of the anchor (avoiding default browser reaction)
$('#tooltip').show(); // show the tooltip
}).mousemove(function(e) // OnMouse mode event
{
$('#tooltip').css('top', e.pageY + 20 ); // tooltip 20px below mouse pointer
$('#tooltip').css('left', e.pageX - 100); // tooltip with mouse pointer
}).mouseout(function() // OnMouseOut event
{
$(this).attr('title',$('#tooltip').html()); // set the title back to initial value
$(this).children('div#tooltip').remove(); // get rid of the tooltip container
});
})
Conclusion
This web site provides two types of tooltip-enabled anchors: standard and pseudo hyperlinks. The initial intent was to use CSS only to enable the tooltips but clipping of the tooltip occurred when the link was located near the edge of the page.
This problem was corrected using DHTML, i.e., Javascript code that changes the CSS dynamically. After a few alternative solutions, the algorithm that uses one "tooltipholder div element with a single fixed "id" was selected. It has been used on this web site for a while and appeared to be cross-browser compliant based on the limited tests that I could perform.
However, this solution was put aside when I discovered the capabilities of the jQuery Javascript library. The code is simple and it uses the "title" attribute of the anchor. Scripting the toolkit-enable anchor just requires an anchor of class "trigger" with a non-empty "title" attribute and it is done.