This article was originally posted on DigitalSynopsis. Viktor Hertz, a…
Tooltips are a great way to enhance a UI when your users need some extra context for that fancy icon, or when they want some reassurance for clicking a button, or maybe an Easter Egg caption to go along with an image. Let’s make some animated tooltips, right now, with nothing but HTML and CSS.
Table of Contents
- 0.1 Demo
- 0.2 A Note About Accessibility and Capability
- 0.3 Let’s Set Some Expectations
- 0.4 Alright! Let’s Rock This Boat!
- 0.5 Ain’t No Party Like A Tooltip Party!
- 1 Attribute Selectors; A Quick Refresher
- 2 Now Entering Tooltip Alchemy
- 3 1. Relativity
- 4 2. Pseudo-element Prime Time
- 5 3. The Dink
- 6 4. Bubbles!
- 7 5. Interaction Action
- 8 6. Flow Control
- 9 7. Animate All the Things
- 10 Conclusion
Here’s what we’re working towards:
Before we get immersed in the cauldron, let’s take a peek at what we’re actually brewing. The main goal is to have a simple way to add a tooltip, so we’ll do that by adding a custom
A Note About Accessibility and Capability
If you are looking for 508-compliant tooltips, or need smarter tooltips with container collision detection and/or support for HTML content vs. plain text, there are plenty of solutions that use third-party scripts to solve those needs for you.
This tutorial doesn’t specifically address accessibility needs. You know your users and what they need, so be sure to consider their needs in this respect too.
Let’s Set Some Expectations
- We’ll be using attribute selectors (not classnames), with CSS built-in pattern matching
- Add to existing DOM elements (no new elements required in your markup*)
- Code examples are prefix-free (add vendor prefixes for your target browsers if needed)
- Assumes mouseover/hover to trigger tooltips
- Plain text tooltips only (HTML, images, etc. are not supported)
- Subtle animations while invoking tooltips
Alright! Let’s Rock This Boat!
Oh, wait. We have an asterisk to deal with first, about “not needing any extra markup”. This is magic, after all. Our tooltips don’t really need any extra DOM elements as they are made up completely of pseudo-elements (the
::after things) which we can control via CSS.
If you’re already utilizing an element’s pseudo-elements from another set of styles and you want a tooltip on that element, then you may need to restructure a little bit.
Ain’t No Party Like A Tooltip Party!
Wait. Gremlins! One more caveat: CSS positioning. In order for the tooltips to function properly, their parent element (the thing to which we are attaching the tooltip) needs to be
position: relative, or
position: absolute, or
Basically, anything other than
position: static — that’s the default position mode assigned to pretty much all elements by the browser. The tooltips are positioned absolutely and so they need to know the boundaries in which their absoluteness has meaning. The default position directive static does not declare its own boundaries and will not give our tooltips a context to push against, so the tooltips will use the next closest parental element that does have a declared boundary.
You’ll need to decide which position directive works best with how you are using the tooltips. This tutorial assumes
position: relative for the parent element. If your UI relies on an absolutely positioned element, then some restructuring (extra markup) may also be needed to deploy a tooltip on that element.
Let’s jump in and see what’s up.
Attribute Selectors; A Quick Refresher
Most CSS rules are written with classnames in mind, like
.this-thing, but CSS has a handful of selector types. Our magic tooltips are going to use attribute selectors–that’s the square bracket notation:
When the browser encounters something like this:
it will know it needs to apply the
[foo] rules because that
<span> tag has an attribute named foo. In this case, the span itself would have a translucent-black background with white text.
HTML elements have various built-in attributes, but we can also make up our own. Like
tooltip. By default, HTML doesn’t know what these mean, but with CSS we can tell HTML what this means.
Why Attribute Selectors?
We’ll use attribute selectors primarily for a separation of concerns. Using attributes over classnames does not get us any bonus points in the specificity wars; classes and attributes have the same specificity. However, by using attributes we can keep our content with the content as HTML attributes can have values, whereas classnames do not.
Consider the classname
.tooltip vs. the attribute
[tooltip] in this example code. The classname is one of the values for the attribute
[class] while the tooltip attribute has a value, which is the text we want to display.
Now Entering Tooltip Alchemy
Our tooltips will use two different attributes:
tooltip: this holds the tooltip’s content (a plain text string)
flow: optional; this allows us to control how to expose the tooltip. There are many placements we could support but we’ll cover four common placements:
up, left, right, down.
Now, let’s set up the ground work for all tooltips. The rules from steps 1–5 apply to all tooltips regardless of what flow we give them. Steps 6–7 have distinctions between the various
This is for the tooltip’s parent element. Let’s assign a position directive so the absolute positioning of the tooltip’s parts (the
::after pseudo-elements) are positioned in context of this parent element and not in context of the page at-large or a grandparent element or some other outer element up the DOM tree.
2. Pseudo-element Prime Time
It’s time to prime the pseudo-elements. Here we’ll set common properties to both the
::after pieces. The
content property is what actually makes a pseudo-element work, but we’ll get there soon.
3. The Dink
I don’t know why “dink” makes sense, I’ve just always called it that. This is the little triangle pointy part that gives the tooltips their speech bubble feel by pointing at the thing which invoked it. Notice we’re using
transparent for the border color; we’,ll add in the color later as how we add it depends on the tooltip’s
It’s not a typo that the
content: ''; declaration has an empty string for a value. We don’t want anything in there, but we do need that property for the pseudo-element to exist.
To make a triangle we are defining a solid border with some thickness on an empty box (no content) with no width and no height, and only giving one side of the box a border color. For more details check out the following tutorial:
Here is the meat of the thing. Notice the
content: attr(tooltip) part saying, “This pseudo-element should use the value of the
tooltip attribute as its content.” This is why using attributes over classnames is so great!
z-index values for both the dink and the bubble. These are arbitrary values, but keep in mind that a
z-index value is relative. Meaning: a z-index value of 1001 inside an element with a z-index of 3 just means that the 1001 element will be the top-most element inside that z-index: 3 container.
z-index should be at least one step down from the dink’s
z-index. If it is the same as or higher than the dink, you can end up with an inconsistent coloring effect on the dink if your tooltips employ a
For a more detailed look at the z-index property, take a look at the following tutorial:
5. Interaction Action
Our tooltips are activated by hovering the mouse over the element with the tooltip… Almost.
If you look back at our style block in Step 2, you should see that we’ve used
opacity: 0; along with
display: none; for our tooltip parts. We did this so we can use CSS animation effects when the tooltips show and hide.
display property cannot be animated, but
opacity can! We’ll deal with the animations last. If you don’t care for animated tooltips, just wipe out the
opacity: 0; declaration from Step 2 and ignore the animation in Step 7.
The last thing we’ll need that still applies to all the tooltips is a way to suppress a tooltip if it has no content. If you are populating tooltips with some sort of dynamic system (, Angular, or React, PHP, etc.) we don’t want silly empty bubbles!
6. Flow Control
This step can get rather complicated as we’ll be using some not so common selectors to help our tooltips deal with their placements based on their
flow values (or lack thereof).
“Strange things are afoot at the Circle-K.” — Ted Theodore Logan
Before we jump into the styles, let’s take a look at some selector patterns we’ll be using.
This is telling the browser: “For all elements with a
tooltip attribute that either do not have a
flow attribute, or have a
flow with a value that starts with ‘up’: apply these styles to its
We’re using a pattern here so these can be extended to other flows without needing to repeat so much CSS. This pattern
flow^="up" is using the
^= (starts with) matcher. This allows the styles to also apply to up-right and up-left should you want to add those flow controls. We’re not going to cover those here, but you can see them in use on my original tooltip demo on CodePen.
Here are the CSS blocks for all four flows this tutorial covers.
7. Animate All the Things
Animations are amazing. Animations can:
- help users feel comfortable
- help users with the spacial awareness of your UI
- call attention to things that need to be seen
- soften elements of a UI that would otherwise be a binary on/off jarring effect
Our tooltips will fall into that last description. Rather than having a text bubble pop into existence and pop out in a flash, let’s make them softer.
We’ll need two
@keyframe animations. The up/down tooltips will use the
tooltips-vert keyframe, and the left/right tooltips will use the
tooltips-horzkeyframe. Notice in both of these keyframes we are only defining the desired ending state of the tooltips. We don’t need to know where they come from (the tooltips themselves have that style information). We just want to control where they go to.
Now, we need to apply these keyframes to the tooltips when a user hovers over the triggering elements (the elements with the
[tooltip] attributes). Since we are employing various flows to control how the tooltips will show, we need to identify those possibilities in the styles.
Use :hover to Pass Control to Animations
Remember we cannot animate the
display property, but we can give the tooltips a fade-in effect by manipulating the
opacity. We are also animating the transform property which gives the tooltips a subtle movement as if they are flying in to point at their triggering elements.
forwards keyword in the animation declaration. This tells the animation to not reset once it completes, but to proceed forward and stay at the end.
Fantastic job! We covered a lot in this tutorial, and now have a neat collection of tooltips to show for our hard work:
We’ve only scratched the surface of what can be done with CSS tooltips. Have fun playing with them and keep on experimenting, and concocting your own recipes!