Creating pure CSS tooltips with no images or JavaScript is nothing new. I’ve never personally written anything on the topic, but there are plenty of examples and tutorials to choose from.
For a recent project, I had to research the concept of CSS tooltips and find something that suited my needs. I didn’t spend too many hours researching but, from what I could see, most (if not all) solutions available were satisfactory for most cases, but had a few minor flaws.
So in this post I’ll address these minor weaknesses and present what I think might be a more bulletproof solution.
Fixing Problems With CSS Tooltips
I think all CSS tool tips should have the following features:
- No extra HTML
- Avoid using the “title” attribute
- Vertical and horizontal fluidity
- Shouldn’t break when a link spans two lines
- Shouldn’t use percentages for positioning
Let’s summarize why these points are important.
Avoiding Extra Markup
Many of the pure CSS tooltips solutions utilize an extra <span>
element that is initially hidden. This is not necessary and, in my mind, is an obsolete method (even though technically it works in more browsers). Having the extra text in the HTML that way would (I assume) have accessibility problems. So instead we can use a pseudo-element that grabs the value of an attribute on the element being hovered over (more on this below).
Avoiding the “title” Attribute
The next point is about the “title” attribute. Now, if you want a completely cross-browser tooltip, your best bet is to just use a plain old title attribute on the link element, and forget about anything custom. But if you use a custom method, and you’re grabbing a value from an attribute, then you don’t want to use the title attribute. This will cause the tooltip to appear in two different places. Not a huge problem, but I think it’s redundant and sloppy looking.
Use a data- Attribute
So instead of using the title attribute, the best option is HTML5 data attributes (John Resig has a good post on the subject). In short, this is a custom attribute that you create that starts with “data-“. So something like “data-tooltip” is fine, but you can call it whatever you want, as long as it begins with “data-“.
Avoid Breakages
Because pretty much all tool tips are positioned absolutely, this can cause problems if the tooltip is not positioned in a bulletproof manner. So although it might be nicer looking when the tooltip appears in the middle or at the end of the element it’s referencing, a better solution is to make the tooltip appear near the top left corner of the link. This ensures that the tooltip doesn’t appear in the wrong place (for example, when the link spans two lines). To avoid this problem, some have used white-space: nowrap
on the links, but I don’t think that’s good, especially if you have links that are longer than one or two words.
Avoid Percentage Units
Another thing I’ve noticed with a lot of tooltip solutions is that they rely on percentages to position the tooltip. This seems like a good way to do it because sometimes you don’t know the size of the element that the tooltip references. But I think it’s best to use em units for this, and you’ll see this in the example below.
A Near Bulletproof Solution?
I have no idea if this solution is bulletproof. Maybe there are problems that I haven’t thought of, but after reviewing the bugs in the other solutions, here’s what I’ve come up with:
<
p class=”codepen” data-height=”687″ data-theme-id=”461″ data-default-tab=”result” data-user=”impressivewebs” data-slug-hash=”OJLrKPv” style=”height: 687px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;” data-pen-title=”Bulletproof CSS Tooltip”>
See the Pen
Bulletproof CSS Tooltip by Louis Lazaris (@impressivewebs)
on CodePen.
And here’s the code:
a[data-tooltip]:link, a[data-tooltip]:visited { position: relative; text-decoration: none; border-bottom: solid 1px; } a[data-tooltip]:before { content: ""; position: absolute; border-top: 1em solid #0090ff; border-left: 1.5em solid transparent; border-right: 1.5em solid transparent; display: none; top: -1em; } a[data-tooltip]:after { content: attr(data-tooltip); position: absolute; color: white; top: -2.5em; left: -1em; background: #0090ff; padding: .25em .75em; border-radius: .5em; white-space: nowrap; display: none; } a[data-tooltip]:hover:before, a[data-tooltip]:hover:after { display: inline; }
Here are some notes on the code:
- I’m using the attribute selector to target only links that have a
data-tooltip
attribute - The text shown for the tooltip is whatever value the
data-tooltip
attribute has - I’m using
border-bottom
for link underlining becausetext-decoration
adds underlining to the tooltip, too - Works in IE8+ and everywhere else, as far as I can see
- The tooltip is created using a CSS pure triangle shape and a rounded-corner box (old browsers degrade to square corners)
- I’m using
display: none
, which avoids scrollbars due to overflow in certain cases. - The tooltip is positioned relative to the top left corner of the element, keeping it from breaking when the link spans two lines; the top left corner is always constant
- The tooltip is positioned using ems, which, in this case I think is more bulletproof than percentages. The ems are based on the body font size (or parent font size). The slider in the demo shows how this works.
Feedback?
If this can be improved in any way, please let me know. I’m also aware that other solutions may have other benefits I haven’t thought of. So if you notice anything I’m overlooking, I’d love to make this a more complete discussion of pros and cons for pure CSS tooltips. I’ll do my best to make any necessary improvements.
Great post, Louis.
Using relative units like ems to manage the positioning of the tooltip may be more future proof, as you will have less to worry about in terms of the tooltip covering its parent at different font sizes.
My biggest concern is the accessibility of using the data-* attribute – is it something screenreaders pick up on? Should the tooltips be reserved only for non-essential information, as the pseudo-elements are?
Also, I’m sure you’ve seen the bug, but Webkit’s lack of support for transitions on pseudo-elements has been reported to Chromium:
http://mopo.ws/H5CyWO
and to Webkit:
http://mopo.ws/HFWkfa
Hopefully if more people get involved something will finally be done about it!
Just built http://cssarrowplease.com for creating css for the arrows – could easily be combine with this :)
Neat tool! Thanks for sharing that.
http://cssarrowplease.com redirects to [link removed] ?
Seems fine to me. Maybe your browser is hijacked? (I removed the link so as not to feed their spam)
using visibility:hidden as opposed to display:none will have no real effect on the tooltip, only on trying to animate it,
since you cannot animate/transition display, so using visibility was the better choice there.
There’s also an open bug from 2 years ago to get Chrome to support transitioning pseudo elements.
Actually, it doesn’t seem like you can animate the “visibility” property. See here:
http://jsbin.com/ameziw/edit#html,live
I think technically it is transitioning/animating. But because of the nature of “visibility” and the fact that it has no intermediary states (i.e. there’s no “semi-visibility” like there would be for opacity), then all you see is a sudden change, instead of a transition.
It is on the list of “animatable” properties (http://www.w3.org/TR/css3-transitions/#animatable-properties-) but doesn’t seem to visibly animate.
ah, my mistake, I meant that by setting visibility:hidden as opposed to display:none, you can then transition other properties on it, like specifically opacity
No, not at all. You didn’t make a mistake, you were right. It’s just not appearing to animate, even though it is animating.
Louis, you could try toggling opacity instead of visibility in order to see a smooth transitioning. For older IE versions, you can toggle the visibility/display as a fallback.
I tried that, but here’s how it looks:
http://jsbin.com/oheqoh/edit#html,live (need to view in FF)
It’s because of the two elements overlapping each other, looking awkward. If anyone can make it look nicer, I’ll be glad to update the post.
Louis, I made some quick adjustments, please check http://jsfiddle.net/catalinred/2KQ8G/1/
In Firefox, the only one (for now) that allows animations for generated content, you’ll see the fading effect using
opacity
transition.Also, notice
pointer-events: none
that fix triggering the tooltip when hovering on top of the link.Hope that helps!
Interesting, will definitely revisit once I need this.
There’s one “feature” I’d like to add to your list: tooltips should not take up any real width, meaning they should not trigger any scrollbars if they are on the edge of the screen. Some solutions have that problem but yours doesn’t, which is great.
Very well written. I have been digging for a solution for pure css tooltips for a while now and have encountered all the bugs you mention but have not had the gumption to actually figure out any solutions!
Thanks so much for sharing!
Great Example. Already have a place I’m going to use this. Thanks!!!
FYI, Brian McAllister wrote about this in June 2010
http://www.frequency-decoder.com/2010/06/21/css-tooltips-using-generated-content-and-html5-data-attributes
Thanks. I guess I unknowingly ripped him off. :)
And unlike many (all?) of the others I’ve seen, his actually works well with links that span two lines. I don’t care for the tooltip appearing below the text, but that’s easy to change anyhow.
Chrome does a nice job of centering the tooltip when it is on one line, and pinning it to the left when it is over multiple lines: http://jsbin.com/uzazuf/2/ …other browsers, not so much.
Worth noting that Firefox seems to be buggy and can mess up the positioning of the tooltip if the first word of the element it is applied to is the first word of a new line: http://jsbin.com/uzazuf/2/
And remove the `white-space: nowrap` declaration is important IMO.
Oooh… that’s an interesting little bug in FF. Thanks for catching that.
I fixed it by making all the tooltip links ‘inline-block’:
http://jsbin.com/uzazuf/4/edit#html,live
I’m really not sure if that will have other undesirable effects. What do you think?
And I did think about removing ‘nowrap’, because of the effects a long line might have, but I felt that generally these tips aren’t supposed to be that lengthy anyways. But I’ll fiddle with it and see what I can do. Thanks for the feedback.
And I just realized that inline-block has the same effect as nowrap on the links, so it’s back to square one for double-line links.
Of course, Firefox shouldn’t really be doing that. Should probably be reported as a bug.
I’ve reported the FF bug here:
https://bugzilla.mozilla.org/show_bug.cgi?id=743599
nice tool
learning css
This doesn’t work right on Safari 5.1.5 (maybe this is the bug that Larry Botha was referring to in his comment?). The tooltip displays correctly, but only part of it is erased when you move off.
Does work fine on Chrome 18, Firefox 11, Opera 11.62, Camino 2.1.2, IE9, and Sleipnir 3.3. Bummer that it doesn’t work on Safari, as I’d’ve have started using it otherwise.
Neil, I’ve tested on Safari 5.1.5 (on PC) and I don’t see that problem. You mention “Sleipnir” so I guess you’re on a Mac. Would be good to know if others experience this issue on a Mac.
I’ve been using a pretty similar approach. The one little sprinkle of fairy dust I recommend is to have the opacity of the tool tip ease in on the hover state.
This adds a little animation effect, and is less jarring visually.
The reason I’m not using opacity is because in order to use that, you have to have the tooltip exist as a hoverable element before it appears. So the user could be hovering over random areas around the link (where the tooltip is hidden) and then just by hovering over the invisible tooltip area, this will make the tooltip appear.
Maybe there’s something I’m overlooking here, but it seems that visibility or display are the only options in this case.
Is there some way to make the tooltip text multi-line? In my case, I am trying to use it on a calendar to provide a bit more info about each event. I tried putting <br /> inside the data-tooltip but it just displayed the html. I want to put
EventName<br />StartAndEndTime<br />RoomName
all in the tooltip…so i need three lines of text.Sorry for the late reply.
The only quick solution I can think of for this is to do this:
http://jsbin.com/uyitot/edit#html,live
I’ve removed the “white-space: nowrap” to keep the line breaking naturally, and I’ve added a set width. The width constrains the line and forces it to break into two lines. You could also have a ‘max-width’ to ensure it’s still flexible within a certain range I suppose…?
Thanks! This does successfully make a multi-line tooltip…but I still cannot control where the line breaks. I suppose I could dynamically add a bunch of
& nbsp;
to force wrapping at a certain point based on the width of each character of my font…but that will produce VERY ugly code. Maybe I could wrap each line within a span or something? That would still make the code messy, but at least would be somewhat logical and legible. I guess the real issue is that the text is treated literally rather than being processed by the DOM. Below are two examples…in each case I have two words on the first line, one on the second, and the rest on the third (maybe wrapping to fourth). Any way to make one of these solutions work? CURRENTLY TRYING THIS (does not work):MAYBE SOMETHING LIKE THIS WOULD WORK?
Is there not a way to have the code within the tooltip “executed”? It looks like the problem is that the browser just outputs literal text rather than interpreting it. Is there no workaround?
No, you can’t do that. You can’t put HTML elements in side of HTML attributes. That will cause the universe to implode! :)
I don’t think there is a way to do what you’re asking for. If you really need that to happen, then I would suggest using a jQuery tooltip that allows this, although I don’t know for sure if any solution would work.
Hi
Same thing i am trying i want to add links in tool tip like this
<a href="#" data-tooltip="Clear Passcode | Lock Device | Wipe Device“>Action
Is it Possible?
No. If you add that sort of thing, then it’s not really a “tool tip”, it’s a popup menu or something.
You need a jQuery script or something, this one is just a simple tip, nothing more.
Mine is appearing way at the top of the page in Google Chrome on Mac, not near the hyperlink it’s supposed to be providing the tip for.
http://thinkdifferenthosting.com/eberle/?page_id=187#
The problem is that your CSS is declaring the styles for
li[data-tooltip]
instead ofa[data-tooltip]
. If you add the following CSS before all your tooltip styles, it should fix it:Thanks so much! That did the trick!
This works great in all browsers but not IE8. Is there a way to make this work in IE too?
I have a native install of IE8 on Windows 7 and it works fine for me. The only thing missing is the rounded corners. Doesn’t work on IE6/7 though.
I have IE 8 and Windows XP.
Okay, so what happens exactly? What do you see? Does anything appear when you hover?
Also, make sure that your IE8 is not in “IE7 mode”. If you have the IE developer tools installed, open it and check that it’s not in “IE7 mode” and not in “compatibility mode”. You might also have your IE8 set up by default to view all pages in compatibility mode, which I think is possible, if I remember correctly.
Thank you!
CSS CODE:
HTML CODE:
This code works fine for me in IE8. But you shouldn’t put that much text in the tooltip. It kind of defeats the purpose. It should just be a simple text tip. For extended tips like this, I would recommend a JS/jQuery solution instead.
See my previous comment about IE’s compatibility mode, because that’s the only reason I can think of that you’re not seeing the tool tip in IE8.
Oh my gosh!!! I have IE 8 but you were right it was set to IE7.
Yeah, that has driven me crazy in the past too. And even just now when I was testing your code, I almost forgot to correct the IE7 mode myself and was wondering why it wasn’t working for a few seconds there! :)
Very well done. You might consider using .1em for the border-bottom to make the text look like an underlined link. It will scale better if larger font sizes are used for the anchor.
I didn’t like how the border-bottom looked (spacing was off), so I added the following CSS, which removes the underline when the anchor is hovered so it doesn’t appear in the pseudo elements:
a[data-tooltip]:hover { text-decoration:none; }
This looks really neat, but I don’t understand why it’s not displaying correctly in IE8 for me?! Any ideas on what I can check, I’m def not in the compatibility mode, I have IE8 installed on an old laptop I’m using to check…
Thanks
In relation to my above comment, here’s my page:
http://dev.racketstringer.co.uk/order-tennis-2.html
Working fine in Safari, but IE8 doesn’t seem to be working :-( any suggestions?
Well, you have bigger problems than that. It’s not working properly in Chrome or Safari on PC, and it doesn’t show up at all in Firefox or Opera.
I’ll take a closer look and see if I can figure out what the problem is, because it seems you’ve done something to mess it up, but I can’t figure it out from glancing at the CSS.
After examining it, you’ve got many problems. Your code has totally changed the positioning of the tooltip. For example, the “left” and “right” values should be basically the same as what I have in my example, otherwise it won’t work. You’ve also removed the “white-space” property that keeps the width of the element.
You also don’t need “width: 100%” which you’ve added to the links.
The best thing to do is copy and paste my code to replace all of yours, and then modify mine to suit your needs. But don’t change the positioning values, except maybe a few pixels or so.
Hope that helps. :)
Hi Louis
Thanks for your help! I had all sorts in my css so completely reset with your code and got it working fine! One question – is it possible to include an image within the tooltip?!
Thanks
Adam
No, images won’t work with this because it’s grabbing the data out of an HTML attribute, so it can only be text.
Ah fair enough. On your travels to make this brilliant tool tip did you find any others that allow you to include an image that worked well across all browsers?
Thanks
I don’t know if this is what you’re looking for:
http://cssglobe.com/post/1695/easiest-tooltip-and-image-preview-using-jquery/
Try googling “tooltip with image” for others.
I’d like to use this to style tool tips on a form, but I need them to pop up when a user mouses over a field (containing both text and input or selects elements) and I’m having trouble figuring out how to insert it.
Is there a way to use this in that manner and/or apply this code to ‘Title’?
Yes, just change “data-tooltip” in the code to “title”. Just make sure you change it in the CSS, and alter the CSS selectors, which now reference “a” elements. You’d have to change them to “input” or whatever.
But to be honest, I don’t know why you’d need to do that. The “data-tooltip” attribute will work on any element exactly the same way, so you can use “data-tooltip” but just change the selectors only, and the attr() value in the CSS.
I tried adding it to several elements, including text boxes, and removed the ‘a’ before [data-tooltip] in the CSS but I can’t seem to get it to work properly when it’s not part of a link.
I created a sample with a text box that isn’t working along with a working link at http://jsbin.com/ezowez/1/edit
Oh, duh. I’m sorry, you can’t do it on those types of elements.
I completely forgot that this technique is using pseudo-elements, What a pseudo-element does is add a new element *inside* the element it applies to (inside, as in, as a child element). So if the element it’s applied to is a replaced element or image (where it can have no children) then it won’t work. That’s just a fact of life when it comes to pseudo-elements.
Sorry to lead you on there, I just wasn’t paying attention to your question close enough. :)
No problem, and I really appreciate how quickly you got back to me :-)
And now we’ve discovered one reason that it might be useful to use the Title ;-)
Right, or else just use a tooltip that’s using jQuery or something so it doesn’t rely on pseudo-elements. :)
exelente
Hey there Louis, great article! I’ve been working on implementing CSS tooltips this morning and your article helped me clear up a few issues. However, I came up with a couple of changes that I think make your tooltips a bit more extensible and bulletproof. There’s a link to my full article on it at the bottom of this comment, but here’s the jist of it.
Use
display:none/block;
instead ofvisibility:hidden/visible;
. I saw a really strange bug with thevisibility
attribute in IE8 which caused the text to remain hidden when the link was hovered over. I’m not sure what caused that since it seems to work fine in your demo, but switching over todisplay
rectified the problem.Use
bottom:0;
instead oftop:x;
. Then usemargin-bottom
with a value equal to the content the tooltip is attached to, i.e. 1em to make it hang over your text, 10px to hang over a 10px icon, a little jQuery magic to hover over fluid height elements.You can check out my JSBin here:
http://jsbin.com/owupil/9/edit
You can check out my full article on it here:
http://trezy.com/blog/pure-css-tooltips-now-with-more-awesome/
That’s interesting. I’ll have to take a closer look when I get a chance. Thanks for letting me know about it! :)
Hy.
I would like to know if it is possible instead of put the tooltip in a element ‘a’ of a text if it is possible to attribute the tooltip to a table row.
tanks.
I’m not sure what you mean. Can you give me a code example or something that shows what you’re trying to do?
I think this might help you out, José: http://jsbin.com/idekus/1/
Unfortunately, you won’t be able to use a CSS arrow on your tooltip in this case because using the :before pseudo-class would put your arrows on the left of the tr rather than just on the left of the tooltip. You could, however, use an extra element in your table to accomplish your goal like this:
http://jsbin.com/idekus/2/
or this:
http://jsbin.com/idekus/6/
In the second example, your arrow will have to stay inside the last cell, otherwise it win’t quite match up with your tooltip. I recommend against the last example because you’re using an extra empty cell in your table. Tables are already THE DEVIL. In your case I would definitely recommend going for a Javascript/jQuery solution.
Seems to work in all modern browsers just fine, but my client is running IE7 and the hover overs are not working. I switched the visibility over to display, still no luck. Any suggestions?
Hey, Matt. These tool tips work in IE8+, because pseudo-elements don’t work in IE7. I think you should tell your client that it’s time to upgrade his 6-year old browser. :)
Thanks Louis for the quick response.
I concur. :)
Note:
If you don’t care about the transition/animation capability, you can do it with less code, like this:
http://jsbin.com/ajutil/359/edit
Credit to Gonzo:
http://www.gonzoblog.nl/2013/03/27/a-super-simple-and-sexy-tooltip-only-css/
This is an excellent example. One Question: How do you make the arrow point to right center of data content?
Example: “SOME DATA” [arrow pointing to data]
I tried to manipulate top and left as suggested in other articles w/o success.
Respectfully……….
can this be applied to image maps? im trying to create a pure css tooltip on image maps so far no luck
No, because pseudo-elements cannot be applied to an image. They can only apply to elements that contain stuff, which have opening and closing tags.
Hi Louis, many thanks for this. I found adding a fixed width in pixels (for me, 200px) and changing white-space to ‘pre-line’ rather than ‘wrap’ gave me what I wanted i.e fixed width tooltips that would handle longer text lengths by wrapping to new lines and increasing in height/depth.
I did find that having bigger tooltips that spread out and trigger the hover behaviour too widely (and possibly even over other elements that need a tooltip) was a problem, as Louis highlighted and hence went with visibility instead of opacity. Solution? Use both. Toggle the visibility between hidden and visible and also use opacity with a transition, you get the best of both i.e. no spreading of the hovered area but a nice delay and then fade in for the tooltip. I’ll just post all my code, many thanks to Louis for getting this up and running:
[data-tip] {
position: relative;
}
[data-tip]:before {
content: "";
position: absolute;
border-bottom: 5px solid #7E57C2;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
visibility: hidden;
opacity: 0;
transition: opacity 1.0s ease-out;
top: 30px;
left: 40px;
}
[data-tip]:after {
content: attr(data-tip);
position: absolute;
color: #333;
z-index: 1100;
font-size: 10px;
border: 1px solid #DDD;
padding: 10px 7px;
line-height: 16px;
left: 10px;
top: 40px;
background-color: white;
padding: 5px 15px;
white-space: pre-line;
width: 200px;
visibility: hidden;
opacity: 0;
transition: opacity 1.0s ease-out;
}
[data-tip]:hover:before, [data-tip]:hover:after {
visibility: visible;
transition: opacity 0.6s ease-out 2.5s;
opacity: 1;
}