Nuclear Targeted Footnotes

Published 2 weeks, 2 days past

One of the more interesting design challenges of The Effects of Nuclear Weapons was the fact that, like many technical texts, it has footnotes.  Not a huge number, and in fact one chapter has none at all, but they couldn’t be ignored.  And I didn’t want them to be inline between paragraphs or stuck into the middle of the text.

This was actually a case where Chris and I decided to depart a bit from the print layout, because in print a chapter has many pages, but online it has a single page.  So we turned the footnotes into endnotes, and collected them all near the end of each chapter.

Originally I had thought about putting footnotes off to one side in desktop views, such as in the right-hand grid gutter.  After playing with some rough prototypes, I realized this wasn’t going to go the way I wanted it to, and would likely make life difficult in a variety of display sizes between the “big desktop monitor” and “mobile device” realms.  I don’t know, maybe I gave up too easily, but Chris and I had already decided that endnotes were an acceptable adaptation and I decided to roll with that.

So here’s how the footnotes work.  First off, in the main-body text, a footnote marker is wrapped in a <sup> element and is a link that points at a named anchor in the endnotes. (I may go back and replace all the superscript elements with styled <mark> elements, but for now, they’re superscript elements.)  Here’s an example from the beginning of Chapter I, which also has a cross-reference link in it, classed as such even though we don’t actually style them any differently than other links.

This is true for a conventional “high explosive,” such as TNT, as well as for a nuclear (or atomic) explosion,<sup><a href="#fnote01">1</a></sup> although the energy is produced in quite different ways (<a href="#§1.11" class="xref">§ 1.11</a>).

Then, down near the end of the document, there’s a section that contains an ordered list.  Inside that list are the endnotes, which are in part marked up like this:

<li id="fnote01"><sup>1</sup> The terms “nuclear” and atomic” may be used interchangeably so far as weapons, explosions, and energy are concerned, but “nuclear” is preferred for the reason given in <a href="#§1.11" class="xref">§ 1.11</a>.

The list item markers are switched off with CSS, and superscripted numbers stand in their place.  I do it that way because the footnote numbers are important to the content, but also have specific presentation demands that are difficult  —  nay, impossible — to pull off with normal markers, like raising them superscript-style. (List markers are only affected by a very limited set of properties.)

In order to get the footnote text to align along the start (left) edge of their content and have the numbers hang off the side, I elected to use the old negative-text-indent-positive-padding trick:

.endnotes li {
	padding-inline-start: 0.75em;
	text-indent: -0.75em;
}

That works great as long as there are never any double-digit footnote numbers, which was indeed the case… until Chapter VIII.  Dang it.

So, for any footnote number above 9, I needed a different set of values for the indent-padding trick, and I didn’t feel like adding in a bunch of greater-than-nine classes. Following-sibling combinator to the rescue!

.endnotes li:nth-of-type(9) ~ li {
	margin-inline-start: -0.33em;
	padding-inline-start: 1.1em;
	text-indent: -1.1em;
}

The extra negative start margin is necessary solely to get the text in the list items to align horizontally, though unnecessary if you don’t care about that sort of thing.

Okay, so the endnotes looked right when seen in their list, but I needed a way to get back to the referring paragraph after reading a footnote.  Thus, some “backjump” links got added to each footnote, pointing back to the paragraph that referred to them.

<span class="backjump">[ref. <a href="#§1.01">§ 1.01</a>]</span>

With that, a reader can click/tap a footnote number to jump to the corresponding footnote, then click/tap the reference link to get back to where they started.  Which is fine, as far as it goes, but that idea of having footnotes appear in context hadn’t left me.  I decided I’d make them happen, one way or another.

(Throughout all this, I wished more than once the HTML 3.0 proposal for <fn> had gone somewhere other than the dustbin of history and the industry’s collective memory hole.  Ah, well.)

I was thinking I’d need some kind of JavaScript thing to swap element nodes around when it occurred to me that clicking a footnote number would make the corresponding footnote list item a target, and if an element is a target, it can be styled using the :target pseudo-class.  Making it appear in context could be a simple matter of positioning it in the viewport, rather than with relation to the document.  And so:

.endnotes li:target {
	position: fixed;
	bottom: 0;
	padding-block: 2em 4em;
	padding-inline: 2em;
	margin-inline: -2em 0;
	border-top: 1px solid;
	background: #FFF;
	box-shadow: 0 0 3em 3em #FFF;
	max-width: 45em;
}

That is to say, when an endnote list item is targeted, it’s fixedly positioned against the bottom of the viewport and given some padding and background and a top border and a box shadow, so it has a bit of a halo above it that sets it apart from the content it’s overlaying.  It actually looks pretty sweet, if I do say so myself, and allows the reader to see footnotes without having to jump back and forth on the page.  Now all I needed was a way to make the footnote go away.

Again I thought about going the JavaScript route, but I’m trying to keep to the Web’s slower pace layers as much as possible in this project for maximum compatibility over time and technology.  Thus, every footnote gets a “close this” link right after the backjump link, marked up like this:

<a href="#fnclosed" class="close">X</a></li>

(I realize that probably looks a little weird, but hang in there and hopefully I can clear it up in the next few paragraphs.)

So every footnote ends with two links, one to jump to the paragraph (or heading) that referred to it, which is unnecessary when the footnote has popped up due to user interaction; and then, one to make the footnote go away, which is unnecessary when looking at the list of footnotes at the end of the chapter.  It was time to juggle display and visibility values to make each appear only when necessary.

.endnotes li .close {
	display: none;
	visibility: hidden;
}
.endnotes li:target .close {
	display: block;
	visibility: visible;
}
.endnotes li:target .backjump {
	display: none;
	visibility: hidden;
}

Thus, the “close this” links are hidden by default, and revealed when the list item is targeted and thus pops up.  By contrast, the backjump links are shown by default, and hidden when the list item is targeted.

As it now stands, this approach has some upsides and some downsides.  One upside is that, since a URL with an identifier fragment is distinct from the URL of the page itself, you can dismiss a popped-up footnote with the browser’s Back button.  On kind of the same hand, though, one downside is that since a URL with an identifier fragment is distinct from the URL of the page itself, if you consistently use the “close this” link to dismiss a popped-up footnote, the browser history gets cluttered with the opened and closed states of various footnotes.

This is bad because you can get partway through a chapter, look at a few footnotes, and then decide you want to go back one page by hitting the Back button, at which point you discover have to go back through all those footnote states in the history before you actually go back one page.

I feel like this is a thing I can (probably should) address by layering progressively-enhancing JavaScript over top of all this, but I’m still not quite sure how best to go about it.  Should I add event handlers and such so the fragment-identifier stuff is suppressed and the URL never actually changes?  Should I add listeners that will silently rewrite the browser history as needed to avoid this?  Ya got me.  Suggestions or pointers to live examples of solutions to similar problems are welcomed in the comments below.

Less crucially, the way the footnote just appears and disappears bugs me a little, because it’s easy to miss if you aren’t looking in the right place.  My first thought was that it would be nice to have the footnote unfurl from the bottom of the page, but it’s basically impossible (so far as I can tell) to animate the height of an element from 0 to auto.  You also can’t animate something like bottom: calc(-1 * calculated-height) to 0 because there is no CSS keyword (so far as I know) that returns the calculated height of an element.  And you can’t really animate from top: 100vh to bottom: 0 because animations are of a property’s values, not across properties.

I’m currently considering a quick animation from something like bottom: -50em to 0, going on the assumption that no footnote will ever be more than 50 em tall, regardless of the display environment.  But that means short footnotes will slide in later than tall footnotes, and probably appear to move faster.  Maybe that’s okay?  Maybe I should do more of a fade-and-scale-in thing instead, which will be visually consistent regardless of footnote size.  Or I could have them 3D-pivot up from the bottom edge of the viewport!  Or maybe this is another place to layer a little JS on top.

Or maybe I’ve overlooked something that will let me unfurl the way I first envisioned with just HTML and CSS, a clever new technique I’ve missed or an old solution I’ve forgotten.  As before, comments with suggestions are welcome.


Comments (11)

  1. Idea:
    – Add an event listener to the close/back links.
    – If the current hash in the url matches the footnote hash the click is coming from, then use the history api to go back instead of just doing a normal navigation action.
    – You might also then need to actively refocus/target… maybe not…

    That would, I think, allow you to remove the hash for the footnote from the history. And it should work as a progressive enhancement since your original links would still work without the added listener.

  2. I like that approach, Derik. Seems low-impact. The only question is whether I can figure out how the URL and hash juggling works in JS — the last time I did that kind of thing it was in, uh, PHP. 🤭

  3. window.location.hash is pretty simple. If you need to do more involved URL parsing new URL(window.location) gets you a nice object you can manipulate, which is a ton easier than the old school ways of doing it.

  4. First time commenter, long time reader. Awesome project and, as always, awe-inspiring CSS!

    :target related: Consider a transition of max-height as a workaround for the height animation want. See example by Felipe Fialho.

  5. Sweet Lady of Marscapone, of course max-height is the solution. Why didn’t I think of that?!? Thanks, Justin!

  6. Derik, here’s what I’ve come up with:

    window.onload = function() {
        if (window.history) {
            let closeLinks = document.querySelectorAll('a.close');
            for (let cLink of closeLinks) {
                cLink.addEventListener('click',fncloser);
            }
        }
    }
    
    function fncloser() {
        let caller = '#' + this.parentElement.getAttribute('id');
        let fragID = window.location.hash;
        if (caller == fragID) window.history.back();
    }
    

    This seems to work as expected in my initial testing, so barring any roadblocks from testing in other browsers, I’ll work to get this deployed soon. Thank you!

  7. Nice! Glad to help. I’ve learned a lot from you over the years.

  8. Those are really nice footnotes!

    From a usability point of view, having clicked on a superscript number to view a footnote at the bottom of the screen, I really wanted clicking the number again to remove it — that is for it to be a toggle.

    Intuitively that’s what I tried, even though I’d just read this article and therefore should’ve known it wouldn’t work.

    But even once I’d worked that out, having to move the mouse all the way down to the ‘X’ at the bottom made the actions seem awkwardly asymmetric: “Want a footnote? Just click this handy superscript number right where you are. Want to get rid of it again? Ah, well, you’re going to have to go all the way over there.”

    So if each footnote number could somehow be replaced by a link which removes it, that’d be good — though I don’t have any good ideas how to do that off the top of my head. (I had several ungood ideas, but fortunately realized the issues with each of them before commenting.)

  9. Those are good points, Smyler. I suspect I could do an event listener attach/unattach tango with the footnote links that wouldn’t be too difficult. I should throw in an escape-key listener as well, for keyboard users. Looks like I have a changelist for the next version of the script!

  10. This is such an interesting post with all the contextual decision making and small implementation details. That feels so real (because it is, obviously). A “simple” footnote can sure be awfully complicated!

    I had a bunch of thoughts about potential alternate approaches to small things and a high-level reaction to cap it all off.

    specific presentation demands that are difficult  —  nay, impossible — to pull off with normal markers

    My mind goes to CSS counters with ::before { display: block; position: absolute; right: calc(100% + 2em); content: counter(list-item); /* etc. */ }

    I recently learned that list-item is the default counter set by the user agent, so if you only need to style the regular 1, 2, 3… of an ol, you don’t have to define a custom counter!

    My first thought was that it would be nice to have the footnote unfurl from the bottom of the page, but it’s basically impossible (so far as I can tell) to animate the height of an element

    When I want to animate height, I usually end up finding an acceptable alternative that can use transformY. transformY(100%) is relative to the element’s height and is also optimized by the browser for animating/transitioning.

    So every footnote ends with two links, one to jump to the paragraph (or heading) that referred to it, which is unnecessary when the footnote has popped up due to user interaction; and then, one to make the footnote go away, which is unnecessary when looking at the list of footnotes at the end of the chapter.

    In playing briefly with the footnotes in Chapter 1 on my phone, I pretty quickly lost my place and wanted to use the hidden backjump link. I wonder if there are other use cases for leaving both links.

    when an endnote list item is targeted, it’s fixedly positioned against the bottom of the viewport

    I was thinking about the accessibility of this approach. Since the :target rule pulls footnote to a fixed position, does this violate Focus Order accessibility rules if there is a fixed-position footnote when looking at the list of all footnotes?

    And related to the last point, what impact does hiding the .backjump link have on folks who are trying to move focus from a footnote back to reference link after reading a footnote? That feels like the biggest argument for leaving both links visible at all times.

    And my big picture thought: With footnotes on the web, I always feel a tension between using a jump link approach, a disclosure widget approach (inline expand/collapse) and a tooltip approach. They all have different advantages, though I think tooltips are often viewed as “slicker” (and so some people think “better”…).

    If it walks and talks like a tooltip, then it should be a tooltip which requires JavaScript (shoutout to the incredible “Accessibility Concerns” section on that MDN page!).

    It seems like in this case, there is a real tension in how to faithfully represent the immediacy of footnotes (they’re on the page you are reading) with the lower priority of footnotes (smaller font, bottom of the page). I do like your suggestion of including them in the margin, though that doesn’t solve mobile.

    One thing about footnotes that isn’t represented here is that they are temporary and disappear after you turn the page. They are neither inline nor at the bottom of the page). I have no idea where that leads, but I wonder about some kind of interesting implementation that uses position: sticky in the right-gutter or in a devoted footnote area at the bottom of the viewport.

    So that was a bunch of thinking out loud that was mostly for myself. Hopefully something here is interesting to someone else too :)

  11. Just to quickly follow up on my last comment, here’s a demo of numbered superscript footnotes using a CSS counter. It feels good.

Add Your Thoughts

Meyerweb dot com reserves the right to edit or remove any comment, especially when abusive or irrelevant to the topic at hand.

HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <em> <i> <q cite=""> <s> <strong> <pre class=""> <kbd>


if you’re satisfied with it.

Comment Preview