A Step-by-Step Guide to Making Pure-CSS Tooltips
Tooltips are a ubiquitous feature of modern user interfaces. They provide users with additional information about an element when they hover over or focus on it, without cluttering the page with permanently visible text. Tooltips can be used to clarify the purpose of an icon, display the full text of a truncated element, or provide usage hints for a complex UI component.
While there are many JavaScript libraries available for creating tooltips, it‘s also possible to create quite sophisticated tooltips using pure CSS. In this article, we‘ll dive deep into the technique of creating tooltips with CSS, using step-by-step examples and exploring advanced tips and tricks along the way.
Why Pure CSS Tooltips?
Before we get into the how, let‘s consider the why. Why would you choose to implement tooltips with pure CSS instead of using a JavaScript solution? There are a few compelling reasons:
-
Performance: CSS tooltips require no JavaScript execution, reducing the load on the browser and improving performance, especially on lower-powered devices.
-
Simplicity: With pure CSS, you can create a tooltip with a single HTML element and a few lines of CSS. This simplicity makes your code easier to understand and maintain.
-
Reliability: Because they don‘t rely on JavaScript, CSS tooltips will still work even if JavaScript is disabled or fails to load for some reason.
-
Lightweight: A pure CSS tooltip solution will typically have a smaller file size than a JavaScript library, reducing page load times.
Of course, there are also situations where a JavaScript tooltip solution may be preferable, such as when you need advanced functionality like delayed showing/hiding or interactive tooltips. But for many common use cases, pure CSS tooltips are a smart choice.
The Building Blocks: Pseudo-Elements
The secret sauce of pure CSS tooltips is the ::before
and ::after
pseudo-elements. These special elements allow you to insert content before or after an element‘s regular content, which is perfect for creating tooltips.
Here‘s a basic example:
button::after {
content: attr(data-tooltip);
/* more styling here... */
}
In this CSS rule, we‘re using the ::after
pseudo-element to create a new element after the content of any <button>
element. The content
property specifies what should be displayed inside this pseudo-element. In this case, we‘re using the attr()
function to fetch the value of the data-tooltip
attribute from the <button>
and display that as the content of our tooltip.
We can use the ::before
pseudo-element in the same way, but the new element will be inserted before the button‘s content instead of after.
Step 1: Creating the Tooltip Container
Let‘s start building an actual tooltip. We‘ll begin with a simple button element:
<button data-tooltip="Click here to learn more!">?</button>
We‘ve added a data-tooltip
attribute to hold the text we want to display in the tooltip. You could also use the title
attribute for this, but a data attribute feels more semantic for a purely decorative tooltip.
Now let‘s create the tooltip container with CSS:
button {
position: relative;
}
button::after {
content: attr(data-tooltip);
position: absolute;
bottom: 100%;
left: 50%;
transform: translateX(-50%);
padding: 5px;
border-radius: 5px;
background-color: #000;
color: #fff;
white-space: nowrap;
opacity: 0;
transition: opacity 0.3s;
pointer-events: none;
}
Let‘s break this down:
-
We set
position: relative
on the button to make it the positioning context for the tooltip. This means the tooltip will be positioned relative to the button. -
We use
position: absolute
on the::after
pseudo-element to remove it from the normal document flow and position it relative to the button. -
content: attr(data-tooltip)
displays the value of thedata-tooltip
attribute as the content of the tooltip. -
We position the tooltip above the button with
bottom: 100%
, which places the tooltip‘s bottom edge at the top edge of the button. -
left: 50%
horizontally centers the tooltip over the button, andtransform: translateX(-50%)
adjusts the tooltip‘s position to compensate for its own width. -
We style the tooltip with some padding, a background color, text color, and rounded corners.
-
white-space: nowrap
prevents the tooltip text from wrapping to a new line. -
We initially set
opacity: 0
to hide the tooltip. We‘ll use a transition to fade it in when needed. -
pointer-events: none
makes the tooltip ignore mouse events, so you can hover over the tooltip without it disappearing.
Step 2: Adding a Tooltip Arrow
A tooltip isn‘t complete without a little arrow pointing toward the thing it‘s describing. We can create this arrow with another pseudo-element:
button::before {
content: "";
position: absolute;
top: 100%;
left: 50%;
margin-left: -5px;
border-width: 5px;
border-style: solid;
border-color: #000 transparent transparent transparent;
}
The key parts here are:
- We use an empty
content
property to create an element with no visible content. - We position this element below the tooltip with
top: 100%
. - We create a triangular shape by setting different
border-width
values and making the side borders transparent. - We center the arrow horizontally with
left: 50%
andmargin-left: -5px
.
Step 3: Showing and Hiding the Tooltip
Now we have a tooltip, but it‘s always visible. Let‘s make it appear only when the user hovers over the button:
button:hover::after,
button:hover::before {
opacity: 1;
}
Now, when the user hovers over the button, both the ::after
and ::before
pseudo-elements will transition to opacity: 1
, fading in the tooltip and its arrow. When the user moves their mouse away, the tooltip will fade back out.
Advanced Positioning Techniques
Our basic tooltip appears above the button, but what if we want to position it to the side or below the button? We can modify our CSS to allow for different positioning options.
First, let‘s create some utility classes for different tooltip positions:
.tooltip-top::after {
bottom: 100%;
left: 50%;
transform: translateX(-50%);
}
.tooltip-top::before {
top: 100%;
left: 50%;
margin-left: -5px;
border-color: #000 transparent transparent transparent;
}
.tooltip-right::after {
left: 100%;
top: 50%;
transform: translateY(-50%);
}
.tooltip-right::before {
left: 100%;
top: 50%;
margin-top: -5px;
border-color: transparent #000 transparent transparent;
}
.tooltip-bottom::after {
top: 100%;
left: 50%;
transform: translateX(-50%);
}
.tooltip-bottom::before {
bottom: 100%;
left: 50%;
margin-left: -5px;
border-color: transparent transparent #000 transparent;
}
.tooltip-left::after {
right: 100%;
top: 50%;
transform: translateY(-50%);
}
.tooltip-left::before {
right: 100%;
top: 50%;
margin-top: -5px;
border-color: transparent transparent transparent #000;
}
Now we can add these classes to our button to position the tooltip in different ways:
<button class="tooltip-top" data-tooltip="I‘m a tooltip above the button!">Hover me</button>
<button class="tooltip-right" data-tooltip="I‘m a tooltip to the right of the button!">Hover me</button>
<button class="tooltip-bottom" data-tooltip="I‘m a tooltip below the button!">Hover me</button>
<button class="tooltip-left" data-tooltip="I‘m a tooltip to the left of the button!">Hover me</button>
Performance Considerations
One of the benefits of pure CSS tooltips is their performance. Because they don‘t rely on JavaScript, there‘s no extra scripting overhead. However, there are still some performance factors to consider.
The main performance concern with CSS tooltips is the use of the opacity
property for the fade-in/fade-out effect. When an element‘s opacity is transitioned, the browser has to do extra calculations to composite the element with the content behind it. This can be taxing on the GPU, especially if you have many tooltips on the page.
One way to mitigate this is to use a different transition effect. For example, you could transition the transform
property instead:
button::after {
/* ... */
transform: translateY(10px);
transition: transform 0.3s;
}
button:hover::after {
transform: translateY(0);
}
In this example, the tooltip starts 10 pixels below its final position and slides up into place when hovered. This transform
transition is often more performant than an opacity
transition.
Another consideration is the number of tooltips on the page. If you have hundreds of elements with tooltips, that‘s a lot of extra pseudo-elements for the browser to manage, which could impact performance. In such cases, it might be better to use a JavaScript solution that only creates tooltips as needed.
Accessibility Considerations
When implementing tooltips, it‘s important to consider accessibility. Pure CSS tooltips have some inherent accessibility limitations:
-
Keyboard accessibility: CSS tooltips are typically triggered by hover, which requires a mouse. This means they‘re not accessible to keyboard-only users.
-
Screen reader accessibility: Because the tooltip content is in a pseudo-element, it‘s not part of the regular document flow and may not be announced by screen readers.
If your tooltips contain crucial information, it‘s best to make that information available in a way that doesn‘t rely on hovering, such as in the regular text content of your page. You can still use tooltips as a supplementary visual aid, but they shouldn‘t be the only way to access the information.
For more accessible tooltips, you might consider a JavaScript solution that can provide keyboard interactions and proper ARIA attributes for screen readers.
Responsive Design Considerations
In responsive design, it‘s important to ensure that your tooltips work well on different screen sizes and device types.
One issue you might encounter is tooltips getting clipped on smaller screens. If a tooltip is positioned near the edge of the viewport, parts of it might get cut off. To prevent this, you can use media queries to adjust the tooltip‘s position on smaller screens:
@media (max-width: 600px) {
button::after {
left: 0;
bottom: 100%;
transform: none;
}
}
In this example, on screens smaller than 600px wide, the tooltip will always appear above the button and aligned to the left edge, preventing it from getting clipped on the right side of the screen.
Another consideration is touch devices. On a touch screen, there‘s no hover state, so hovering to trigger a tooltip doesn‘t work. In these cases, you might want to consider an alternative way to present your tooltip content, such as making it permanently visible or providing a button to toggle its visibility.
Conclusion
Pure CSS tooltips are a versatile and performant way to enhance the user experience of your website or application. By leveraging the power of pseudo-elements and some clever positioning techniques, you can create tooltips that are visually appealing, informative, and easy to implement.
However, it‘s important to use tooltips judiciously and with accessibility in mind. Make sure your tooltips are supplementary and not the sole means of conveying important information.
I hope this deep dive into pure CSS tooltips has been informative and inspiring. Remember, the techniques we‘ve covered here are just the beginning. With a bit of creativity, you can create all sorts of variations and enhancements to fit your specific needs.
Happy coding!