Create simple tooltips with CSS and jQuery – Part 2

In a recent tutorial I taught you how to create simple transparent tooltips with a few lines of CSS and jQuery. Today we will build some more advanced tooltips, based on the aforementioned tutorial.

These tooltips will act a little bit smarter than our basic version. The script will skip links with empty or missing title tags, but more important: the tooltips will try to stay in the browser viewport.

So before we start here is a working example.

Lets have a look at last weeks results:

function simple_tooltip(target_items, name){
 $(target_items).each(function(i){
		$("body").append("<div class='"+name+"' id='"+name+i+"'><p>"+$(this).attr('title')+"</p></div>");
		var my_tooltip = $("#"+name+i);

		$(this).removeAttr("title").mouseover(function(){
				my_tooltip.css({opacity:0.8, display:"none"}).fadeIn(400);
		}).mousemove(function(kmouse){
				my_tooltip.css({left:kmouse.pageX+15, top:kmouse.pageY+15});
		}).mouseout(function(){
				my_tooltip.fadeOut(400);
		});
	});
}

$(document).ready(function(){
	 simple_tooltip("a","tooltip");
});

We will leave the $document.ready function untouched and make modifications just to the simple_tooltip function. The first improvement is an if statement which checks if the title attribute is set correctly:

function simple_tooltip(target_items, name){
 $(target_items).each(function(i){
		$("body").append("<div class='"+name+"' id='"+name+i+"'><p>"+$(this).attr('title')+"</p></div>");
		var my_tooltip = $("#"+name+i);

                if($(this).attr("title") != "" && $(this).attr("title") != "undefined" ){

		$(this).removeAttr("title").mouseover(function(){
				my_tooltip.css({opacity:0.8, display:"none"}).fadeIn(400);
		}).mousemove(function(kmouse){
				my_tooltip.css({left:kmouse.pageX+15, top:kmouse.pageY+15});
		}).mouseout(function(){
				my_tooltip.fadeOut(400);
		});

                }
	});
}

Rather simple, now for the tricky part :)
All upcoming code impovements will take place during the mousemove event so I will only display this part for now:

.mousemove(function(kmouse){
	my_tooltip.css({left:kmouse.pageX+15, top:kmouse.pageY+15});
})

Until now the tooltip was always aligned next to the mouse cursor with an offset of 15px. To check if the tooltip would cross the viewports borders we first need to know where the viewports borders are.
Since we align the tooltip at the top right of our mouse we need to know the top edge and the right edge of the browser. Thanks to jQuery this is mere child’s play:

.mousemove(function(kmouse){

    var border_top = $(window).scrollTop();
    var border_right = $(window).width();

    my_tooltip.css({left:kmouse.pageX+15, top:kmouse.pageY+15});
})

The top of the viewport is 0 if you didnt scroll down; if you did scroll down it is 0 + the amount of pixels you scrolled. This value is returned by scrollTop().

To get the right border we just have to ask for the current windows width.

Since we need a little more flexibility we will create variables for the left and top position of our tooltip, as well as a variable for the offset.

.mousemove(function(kmouse){

    var border_top = $(window).scrollTop();
    var border_right = $(window).width();
    var left_pos;
    var top_pos;
    var offset = 15;

    my_tooltip.css({left:left_pos, top:top_pos});
})

Next thing we do is the math to calculate where to position the tooltips:

if(border_right - (offset *2) >= my_tooltip.width() + kmouse.pageX){
	left_pos = kmouse.pageX+offset;
} else{
	left_pos = border_right-my_tooltip.width()-offset;
}

This if statement basically checks if the width of the tooltip plus the x-position of your mouse is smaller than the vieport. If thats the case the tooltip wouldn’t overlap the vieports border and therefore can be aligned next to the mouse.

If thats not the case the tooltip will stay at a fixed x-position.

if(border_top + (offset *2)>= kmouse.pageY - my_tooltip.height()){
	top_pos = border_top +offset;
} else{
	top_pos = kmouse.pageY-my_tooltip.height()-offset;
}

This if statement is the same for the top border. The combined script looks like this:

function simple_tooltip(target_items, name){
 $(target_items).each(function(i){
		$("body").append("<div class='"+name+"' id='"+name+i+"'><p>"+$(this).attr('title')+"</p></div>");
		var my_tooltip = $("#"+name+i);

		if($(this).attr("title") != "" && $(this).attr("title") != "undefined" ){

		$(this).removeAttr("title").mouseover(function(){
					my_tooltip.css({opacity:0.8, display:"none"}).fadeIn(400);
		}).mousemove(function(kmouse){
				var border_top = $(window).scrollTop();
				var border_right = $(window).width();
				var left_pos;
				var top_pos;
				var offset = 15;
				if(border_right - (offset *2) >= my_tooltip.width() + kmouse.pageX){
					left_pos = kmouse.pageX+offset;
					} else{
					left_pos = border_right-my_tooltip.width()-offset;
					}

				if(border_top + (offset *2)>= kmouse.pageY - my_tooltip.height()){
					top_pos = border_top +offset;
					} else{
					top_pos = kmouse.pageY-my_tooltip.height()-offset;
					}

				my_tooltip.css({left:left_pos, top:top_pos});
		}).mouseout(function(){
				my_tooltip.css({left:"-9999px"});
		});

		}

	});
}

$(document).ready(function(){
	 simple_tooltip("a","tooltip");
});

Our script grew a little bigger during this tutorial, but is nevertheless, very lightweight with only 43 lines of code and already can do more than some of the jQuery tooltip plugins out there ;)

Tags: , , ,
59 replies
Newer Comments »
  1. Mark
    Mark says:

    Great work on this. I’m looking to use this on list items – which works for the most part – unfortunately it seems to lose track of the mouse position when hovering over input elements inside the list. Any suggestions to fix this?

    Atom Groom: I havn’t tested this but I believe this will solve your problem, in the line:

    left_pos = kmouse.pageX+offset;

    Changing offset to half of the tooltip’s width should center it on the mouse.

  2. Mark W
    Mark W says:

    This is a great (tool) tip!!

    What would you do if you wanted this to work in conjunction with a Lightbox style image gallery? Generally, the Lightbox takes it’s details for a title from the “title” attribute. This is disabled in the tooltips script so no title is passed when the Lightbox image pops up therefore no image title!

  3. Kriesi
    Kriesi says:

    you could remove the title just while hovering over the image and as soon as you klick the image or leave with the mouse add the title attribute again

  4. Tom R
    Tom R says:

    Great Website and Great piece of code … I am just learning Javascript and using your code to support applications in Oracle Apex. I have the tooltips working fine on pages that are submitted and refreshed. Now I am trying to do Ajax calls and only rewriting part of the screen which contain gif where I use the tooltips. I thought I could just call the simple_tooltip function after I perform the dom element inner html replace to update the tooltips but this doesn’t seem to work. Any ideas on what I would have to do to update the tool tips in the Javascript code ? Any help appreciated.

    Thanks,
    Tom

  5. a3cube
    a3cube says:

    Nice one but shouldn’t the $(“body”).append come after if($(this).attr(“title”) != “”….? I hope get what am saying.
    Like this:

    if($(this).attr(“title”) != “” && $(this).attr(“title”) != “undefined” ){
    $(“body”).append(“”+$(this).attr(‘title’)+””);

  6. jm
    jm says:

    this is great, just what i needed, EXCEPT i was wondering if there’s a way to include images within the tooltip, can anyone get me started on a tweak to allow that?

  7. David W
    David W says:

    Awesome tooltips! :) One thing though, i’d love to be able to impliment a delay on the appearance of the tooltip, but my setTimeout() function seems to be ignored. Oh dear. Any ideas?

  8. David W
    David W says:

    Nevermind, it’s terrible in theory but I just messed about with the code and ugly-hacked this solution:

    my_tooltip.css({opacity:0.85, display:”none”}).fadeIn(3000);
    my_tooltip.css({opacity:0.85, display:”none”}).fadeIn(300);

    but please, if there is a better way I’d love to know! :)

  9. Mark
    Mark says:

    simple and nice!!! thanks!! :) have looked for a tooltip like this for long time… But is there a way to include images in the title???

  10. Harel Seigmann
    Harel Seigmann says:

    Nice tooltip. Managed to figure out a way to get around the refreshing problem when you are changing the title through an ajax call. What I have done is to append a random number to the id of the div so that when section is refreshed, there will always be a new id.

    if($(this).attr(“class”) == “tooltipj”)
    {

    var d = new Date();
    var randomnumber = d.getTime()
    $(“body”).append(“”+$(this).attr(‘title’)+””);
    var my_tooltip = $(“#”+name+i+randomnumber);

  11. Harel Seigmann
    Harel Seigmann says:

    Forgot to add – after your ajax call (updatepanel or whatever), add:
    simple_tooltip(“a”,”tooltip”);

  12. Tom R
    Tom R says:

    Great script … I am using your tooltip for images which I am displaying in a jQuery Accordian resizable DIV. The amount of tooltips on the page is about 40-50 (dynamic). I am running into the problem of having a scrollable div when using a appearing at the bottom of the div. If I have alot of tooltips the browser creates a vertical scrollbar on the right and the page jump down to show the selected entry. It appears the browser thinks the size of the DOM includes the tooltip entries. Which it does. I tried putting a separate table before the bottom of the body tag but that did not seem to help. Any suggestions when I am working with so many tooltip beside dynamically creating each one at mouseover time ????

    Thanks,

    Tom

  13. Sul
    Sul says:

    Thanks for sharing, I have a quick question though? is it possible to make the tool tip clickable. I mean when mouse over the link make the tool tip stay for a period of time to make it clickable.

    thanks for your help

  14. Jordan Garn
    Jordan Garn says:

    Awesome tutorial adds to your previously good one, if your looking for ideas for a new tutorial a good one would be to show the CSS you did for the rounded corners, I’ve done rounded corner before but not stretchable ones.

Trackbacks & Pingbacks

Newer Comments »

Comments are closed.