I remain a little obsessed about the popover
attribute. This innocuous little HTML attribute produces an accessible and design-friendly “popup” UI/UX effect for little effort. I think the “tooltip” is generally the top use case for this feature, which is now well-supported across the board.
First, we looked at how to use popovers for tooltips. Because the anchor positioning API isn’t as well-supported yet, this leveraged JavaScript to do the positioning.
Second, we looked at progressively enhancing footnotes into tooltips. This technique ultimately checked if the browser supported both popovers and anchor positioning and if so would do native popups, otherwise fallback to being a normal footnote, which is perfectly fine.
This time, we’ll look at a tooltip design that just doesn’t require the anchor positioning API or any JavaScript positioning at all. We’ll make the tooltips slide out from the bottom of the screen instead.
I guess I’ll have to admit this is a series:
Article Series
Closed = Footnote; Open = Drawer
This idea of drawer-based popups don’t require this fancy dance of having the content already visible on the page as a footnote. I just really like the idea. In CSS, the ultimately expresses itself like this:
/* Display as a footnote */
[popover] {
display: list-item;
...
/* Display as a drawer */
&:popover-open {
position: fixed;
...
}
}
Code language: PHP (php)
This will ultimately require a bunch of declarations to force the content into both shapes. Such is CSS.
Progressive Enhancement Happens at the Link/Button Level
Footnotes, the “fallback” for this, require an <a>
link to jump down to them. Whereas the popups require a <button>
to work. So we actually need to display both right next to each other:
<a class="footnote-anchor" href="#ref_1"><sup>1</sup></a>
<button popovertarget="ref_1">1</button>
Code language: HTML, XML (xml)
You could do this either-way-around, but here we’ll hide the anchor links by default and only show them if popups aren’t supported:
.footnote-anchor {
display: none;
}
html.no-popovers {
.footnote-anchor {
display: inline;
}
[popovertarget] {
display: none;
}
}
Code language: CSS (css)
We have this no-popovers
class via:
if (!HTMLElement.prototype.hasOwnProperty("popover")) {
document.documentElement.classList.add("no-popovers");
}
Code language: JavaScript (javascript)
The Sliding Door
The trick to a drawer sliding out from the bottom of the screen is:
- Fixed positioning of the drawer
- Translated off the page the height of itself
- Translated on to the page when opened
That largely looks like this:
[popover] {
...
&:popover-open {
z-index: 1;
position: fixed;
inset: auto;
bottom: 0;
left: 0;
margin: 0;
width: 100vi;
padding: 2rem;
background: lavender;
box-shadow: 0 -1rem 5rem oklch(0% 0 0 / 0.33);
animation: slide-open 0.2s;
/* Make sure the popup isn't screen-covering */
max-block-size: 50dvh;
overflow: auto;
}
}
Code language: JavaScript (javascript)
I was thinking we could pull off the slide-in of the drawer using @starting-style
and a transition, but it turns out you can set the starting style of just the open state like we’d need here. Fortunately, we can just call a simple keyframe animation to do the trick:
@keyframes slide-open {
0% {
transform: translate(0, 100%);
}
100% {
transform: translate(0, 0);
}
}
Code language: CSS (css)
Especially nice on mobile, but looks good on desktop too.
The drawer just seems to make sense on the mobile screen. I don’t think positioning the popup next to the button would even be that helpful, the drawer is nicer.
But even on a larger screen it’s still fairly nice. We can take a little extra care to looslely center things a little text-wrap: balance;
doesn’t hurt.
Thanks Chris, I really like this pattern. One potential challenge may be when the popover might overlap and cover the triggering element (the button).
While the popover supports [popover] dismissal out of the box via the Esc key, I think this would still fail WCAG SC 2.4.11 (focus obscured), so as a quick overcome you might wish to consider applying scroll-padding, maybe calculated with the help of a container query and a variable, though if I am not mistaken, chrome has a bug that want let you calculate the popover height.
Yes I thought about that while making this demo. The way I solved it was setting a max-height (max-block-size) on the popover (50dvh) and then putting padding-bottom (padding-block-end) on the content area of that same height. That way there is always room for it.