CodeinWP CodeinWP

Pure CSS Tooltips Revisited

Pure CSS Tooltips RevisitedCreating 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 because text-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.

74 Responses

  1. Larry Botha says:

    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!

  2. Simon says:

    Just built http://cssarrowplease.com for creating css for the arrows – could easily be combine with this :)

  3. lord xeon says:

    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.

  4. Catalin Rosu says:

    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.

  5. Ferdy says:

    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.

  6. 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!

  7. Denny says:

    Great Example. Already have a place I’m going to use this. Thanks!!!

  8. Mohit Bumb says:

    nice tool
    learning css

  9. NeilB says:

    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.

  10. 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.

    
    element:hover {opacity:.9;transition:opacity .3s ease-in;}
    

    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.

  11. WF says:

    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…?

      • WF says:

        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):

        Lorem ipsum dolor sit amet a
        pure CSS tooltip">hover over this link
        elit, sed do eiusmod tempor incididunt ut labore.

        MAYBE SOMETHING LIKE THIS WOULD WORK?

        Lorem ipsum dolor sit amet This isapure CSS tooltip">hover over this link elit, sed do eiusmod tempor incididunt ut labore.

        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.

  12. MulderDSM says:

    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 of a[data-tooltip]. If you add the following CSS before all your tooltip styles, it should fix it:

      
      a[data-tooltip]:link, a[data-tooltip]:visited {
          position: relative;
      }
      
  13. Joanne says:

    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.

      • Joanne says:

        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.

  14. Joanne says:

    CSS CODE:

    
    a[data-tooltip]:link, a[data-tooltip]:visited {
    	position: relative;
    	text-decoration: none;
    	width:100%;
    }
    
    a[data-tooltip]:before {
    	content: "";
    	position: absolute;
    	border-top: 20px solid #70aec0;
    	border-left: 30px solid transparent; /* this makes the boxes arrow on the left transparent */
    	border-right: 30px solid transparent; /* this makes the boxes arrow on the right transparent */
    	visibility: hidden;
    	top: -18px; /* position of arrow from top */
    	left: 200px; /* position of arrow from left */
    }
    
    a[data-tooltip]:after {
    	content: attr(data-tooltip);
    	position: absolute;
    	color: white;
    	top: -150px; /* position of box from top */
    	left: 100px; /* position of box from left */
    	background: #70aec0;
    	padding: 5px 15px;
    	-webkit-border-radius: 10px;
    	-moz-border-radius: 10px;
    	border-radius: 10px; /* radius of box for rounded corners */
    	visibility: hidden;
        width: 400px;
    }
    
    a[data-tooltip]:hover:before, a[data-tooltip]:hover:after {
    	visibility: visible;
    	-moz-transition: visibility 0s linear .3s;
    }
    
     #tooltip a {
    	font-weight: normal;
    	text-decoration: none;
    	color: #000;
    }	
    #tooltip a:hover {
    	background-color:#fff;
    	color: #486e79;
    }
    

    HTML CODE:

    
    <div id="box">
    	<p id="tooltip"><a href="#" data-tooltip="The registered nurse’s personal philosophy of teaching may be largely influenced by past experiences as a learner. For example, if this nurse had excellent learning experiences while in nursing school, and in orientation, specific behaviors and teaching methods may be incorporated into this preceptorship experience. Conversely, if the preceptor had negative experiences, these may influence their approach to working with a student. The nurse manager and nurse educator are resources for the preceptor in this situation.">A registered nurse with three years of experience has  been asked by the nurse manager to precept a nursing student from the local  school of nursing. The RN has experience with students from this nursing  program, as a group of student complete one of their clinical rotations (with a  faculty member) on this unit. As the nurse prepares for this experience, what  should be considered to guide the personal philosophy of teaching?</a></p>
    </div>
    
    • 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.

  15. Joanne says:

    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! :)

  16. Ty Cahill says:

    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; }

  17. Adam says:

    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

  18. Adam says:

    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. :)

  19. Chaya Cooper says:

    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.

      • Chaya Cooper says:

        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. :)

          • Chaya Cooper says:

            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. :)

  20. k-mi says:

    exelente

  21. Trezy says:

    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 of visibility:hidden/visible;. I saw a really strange bug with the visibility 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 to display rectified the problem.

    Use bottom:0; instead of top:x;. Then use margin-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/

  22. José Rocha says:

    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?

    • Trezy says:

      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.

  23. Matt says:

    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?

  24. 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/

  25. Mike Turner says:

    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……….

  26. Eric says:

    can this be applied to image maps? im trying to create a pure css tooltip on image maps so far no luck

  27. 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.

  28. 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;
    }

Leave a Reply

Comment Rules: Please use a real name or alias. Keywords are not allowed in the "name" field and deep URLs are not allowed in the "Website" field. If you use keywords or deep URLs, your comment or URL will be removed. No foul language, please. Thank you for cooperating.

Markdown in use! Use `backticks` for inline code snippets and triple backticks at start and end for code blocks. You can also indent a code block four spaces. And no need to escape HTML, just type it correctly but make sure it's inside code delimeters (backticks or triple backticks).