Under the Hood #7: Floaty Abbreviations!
That’s a single abbr element (on mouseover).
No spans, divs or superfluous elements. No classes. No Javascript. Just CSS.
Unfortunately the cost of this simplicity is that it only works in Firefox 3.1+, Safari 3,
4 / Chrome 1, 2. If you have any of these, then try it out on
this article, which has a number of abbreviations.
I suspect that I am opening a can-of-worms with this one, as the abuse of the
abbreviation element is already bad enough. This will only encourage people to do worse. However, it is an
effect that I’ve long wanted to do, and has only recently become possible for my target-market with the beta
builds of Firefox 3.15
The crux of this is the ability to absolutely position CSS-generated content
(i.e. :before & :after). This has been supported in
Safari for some time. The bug for Firefox was filed in 2004 (That’s
Firefox 0.8). That annoys me beyond description that something that’s part of the CSS2
spec could be left that long, and only now—in 2009—can I actually do the effect (in my favourite browser) I’ve
been wanting to do all this time.
In essence it’s very simple. Just use :before to write the abbreviation’s title before the
abbreviation and position / style accordingly. I’ve tried on and off over the last few years to do this in
Firefox, but it’s simply not possible without absolute positioning. I came up with some clever hacks,
but they all fell down in one major way: they were simply not absolutely positioned, so therefore would not hang
over any bounding box (for long titles at the page edge).
A second problem is being able to target Firefox 3.5 and not Firefox 3, but also include
Safari. Firefox 3 does not include support for the
“nth-child”
CSS selector, whereas Firefox 3.5 (and Safari) does. This works out handily,
as browser support for this selector also matches browser support for absolute positioning of generated content!
Therefore the following selector matches abbreviations with titles, in Firefox 3.5 and
Safari. For Firefox 3, no match would be made, and therefore the browser would fall back
to the default dotted-underline.
abbr:nth-child(n)[title]:hover { ...
There is however, one problem with this: Opera. It freaks out for some reason and offsets the
absolutely-positioned description by the page scroll, as well as other quirks. Opera also doesn’t
support border-radius, giving a rather blunt look. I need to somehow exclude Opera
entirely, but I don’t know of any CSS selector or hack that can do that. I’ve found ones to exclude
Safari specifically, or Opera and Safari, but nothing that can exclude all
versions of Opera.
On to the code!
/* the abbreviation itself */
abbr:nth-child(n)[title]:hover {
/* the abbr element is relative, so that we can absolutely position the `:before` description */
position: relative;
/* the negative margin removes the effect of the padding and border so that the floaty does not nudge
the surrounding content around */
padding: 1px 5px; margin: -2px -6px;
/* use the line-height of the paragraph the abbr is in, instead of the abbr itself.
this keeps the description central when different line-heights are used in p / code / h1 &c. */
color: #235; line-height: inherit;
/* why have borders for something that appears to have none? 1. you may wish to customise, and
2. without the border, the shadow appears detached from the edge! */
border: 1px solid #93a3b9 !important;
/* gecko supports % for border curves, allowing us to have a perfectly round caps regardless of size */
-moz-border-radius: 0 50% 50% 0; -moz-box-shadow: -1px 2px 1px rgba(0,0,0,.5);
/* webkit does not support % for radius, for small fonts the curves disappear.
8px curves will support a minimum 11px font-size. a solution to this is to set line-height to 1.5em
(instead of inherit) above, and then use 0.75em instead of 8px below. this will work if you have a
strict line-height of 1.5em already through your document */
-webkit-border-top-right-radius: 8px; -webkit-border-bottom-right-radius: 8px;
-webkit-box-shadow: -1px 2px 1px rgba(0,0,0,.5); background-color: #93a3b9;
}
/* the abbreviation description */
abbr:nth-child(n)[title]:hover::before {
/* write out the abbreviation description */
content: attr(title);
/* the controversial bit */
position: absolute; display: block;
/* top has to be nudged up because this is *inside* the abbr whose 1px border is offsetting it.
`right: 100%` positions the description hanging out to the left regardless of description width */
height: 100%; top: -1px; right: 100%; padding: 0 5px 0 7px;
/* because of `right` above, the width is technically 0px, therefore `nowrap` is required! */
color: #456; white-space: nowrap; text-indent: 0; border: 1px solid #c3d3e7;
-moz-border-radius: 50% 0 0 50%; -webkit-border-top-left-radius: 8px;
-webkit-border-bottom-left-radius: 8px; -webkit-box-shadow: -1px 2px 1px rgba(0,0,0,.5);
-moz-box-shadow: -1px 2px 1px rgba(0,0,0,.5); background-color: #c3d3e7;
}
I strongly suggest that before putting this code to use, you read up on the proper
way to use the abbreviation element. In short, abbreviations are not for defining terms, but rather expanding on
how a piece of text should be read according to the author’s original intentions.
This code is licenced under a Creative Commons Attribution 3.0 licence; please share and remix this, just include
“Kroc Camen” and/or “camendesign.com” in your CSS comments, thanks.