Footnotes are commonly found in books, where they can appear at the end of every page. In scientific works, their main application is referencing related papers. But they are also used for complementary information or explaining minor aspects in depth. The concept of footnotes is present in content markup languages as well. The comprehensive re­Struc­tured­Text supports them by default while most parsers for Mark­down, which I am using here, provide them on an opt-in basis. Though for non-paginated content as most webpages are, digital footnotes are worse than their paper siblings. In general, they require user interaction: One has to click the reference number to jump to the end of the webpage, where the footnote can be found and read. To go back to the original position in the text, another link must be clicked. This effectively makes footnotes endnotes. The paper equivalent requires no such effort, as the footnotes are at maximum1 a page length away.

But there exists a solution to this nuissance: Sidenotes. These are also used in paper books, although less common. The work of Edward Tufte is a great example on how they can be used in conjunction with illustrations. Consequently, Tufte-CSS was the first project which made me aware of the concept of sidenotes for the web. Considering that monitors nowadays have an aspect ratio of 16:9 or even wider, a single column of text does not make good use of that real estate. So, why not use that empty space to our advantage and improve upon footnotes by using sidenotes instead‽ Well, because HTML does not natively support it and we thus have to overcome a couple of obstacles. Gwern Branwen has published a detailed article which collects different approaches to implementing sidenotes in HTML. And in Semantic sidenotes for the web Koos Looijesteijn discusses which HTML elements may or may not be used to represent sidenotes.

Looking at these implementations I however didn’t find anything to my liking. I want my sidenotes to be compiled from the Markdown footnote syntax into valid HTML which means that the sidenote reference and sidenote itself must be independent.2 In achieving this I’d like to support more than one block element in a sidenote as well. Sidenotes must be accessible by screen readers and have a graceful fallback in RSS/Atom feeds.3 On smaller devices the sidenotes should be hidden by default but toggleable. And finally, they should be usable without JavaScript.4

My implementation

The sidenote reference inside of a paragraph is a simple link to the sidenote by means of an anchor. It itself bears an id as well to allow backlinking from the sidenote.

<a class="sidenote-ref" id="snref:NAME" href="#sn:NAME"><sup>7</sup></a>

The sidenote is wrapped in an <aside>5 and follows the paragraph containing its reference. Therefore it is not inside of a <p> and thus can contain block elements. This is inline with the Markdown syntax for footnotes. Here the reference can be separate from the content of the sidenote as well. At the end of the sidenote is a backlink to the reference.

<aside class="sidenote-def" id="sn:NAME">
	<sup>7</sup>
	<!-- Sidenote Content -->
	<a href="#snref:NAME">↩</a>
</aside>

Without any CSS the sidenote would now already appear at my prefered location for viewing on small screens. Other solutions have them appear inside the paragraph which in my opinion disrupts the reading flow and makes it more difficult to infer if the paragraph is continuing or already at its end. By adding display: none for the sidenote by default and a display: block in combination with the :target selector for the sidenote reference, we can toggle the visibility of the sidenote by clicking on the sidenote reference and the backlink.

To make it a sidenote on larger screens, we can use the good old float: right with a negative margin-right. And too prevent the next sidenote from overlapping a clear: both is added.6 The beauty of this solution is that subsequent sidenotes are if necessary automatically are pushed down to prevent overlap. But at the same point the main disadvantage comes to light: Because in the source the sidenote is not directly next to its reference, it also isn’t in the rendered HTML. It needs to be shifted upwards by using position: relative with a negative top value. But the question is: By how much?

If we wanted to do without any JavaScript, we would need to manually set a different offset for each sidenote. This however seems like a fragile solution when we consider page resizes along with text reflows. Additionally, it would pollute the Markdown source and violate the separation of concerns. Therefore, I opted to use some JavaScript to find the correct offset at runtime.7 The to be published JavaScript code listens on resize events and iterates over the sidenotes in order, looking up their reference by its backlink, calculating the necessary offset while avoiding prior sidenotes if they are closer than the targeted reference. If you make sure to debounce this function and take all margins and paddings into account, it works out quite fine.

Further enhancements

Because I had to use JavaScript anyway, I opted to implement two additional usability enhancements:8

  • When hovering or focusing the reference the sidenote is highlighted and vice versa.
  • On mobile devices not only clicking the backlink closes an open sidenote but also clicking anywhere else.

The implementation still is useable without JavaScript, the downside being that the sidenotes are not directly right next to their references. If you don’t need block elements in your sidenotes, you could consider just using a span directly after the sidenote reference. Then the sidenote would appear at the correct position without the need for JavaScript. Here, however the fallback for small screens would be again having a sidenote in the middle of a paragraph which I don’t like as explained earlier.

There might be two other points for improvement:9

  • Clicking on a sidenote reference jumps to the sidenote due to the use of the anchor link. This may be useful if the sidenote is far away but can be annoying when it isn’t. On the other hand, one probably doesn’t click the sidenote in the latter case anyway.
  • On smaller screens only one sidenote may be visible at the same time due to the fragment identifier in the URL.

Making it accessible

Finally, we need to make the sidenotes more accessible for screen and feed readers alike. For this, I added ARIA roles and the text “Sidenote” at the beginning which is exclusively shown to screen and feed readers. The backlink received an ARIA label and both the number and the backlink are included in the first and respective last block element of the sidenote to prevent vertical spacing in feed readers.

<aside class="sidenote-def" id="sn:NAME" role="doc-footnote">
	<p>
		<span class="sr-only">Sidenote </span>
		<sup>7</sup>
		<!-- Sidenote Content -->
		<a href="#snref:NAME"
		   role="doc-backlink"
		   aria-label="Back to reference 7">↩︎</a>
	</p>
</aside>

I will publish a cleaned up version of the HTML, CSS and JavaScript at some point. But at the moment, I am still testing if everything works as expected and aim to also reliably support fullwidth figures in combination with sidenotes and possibly other elements in the margin.