Sidenotes in Hugo
As you may or may not know, I use Hugo to handle this blog. Something that I wanted to add, but had no native way of doing, was sidenotes. I like to add extra explainations on some of the articles I write, for that reason, I started my search to implement accessible side notes that, on top of that, work reasonably well on mobile. (sidenote: If I didn't, or if you see something that could be improved or isn't accessible enough, let me know! )
As you can see above, the text that’s been annotated shows up with (sidenote: I wanted to make it stand out that something is up with this text, the underline may make you click it or hover it. )
On screens big enough, the side note is shown on one of the sides depending if I use left or right as first attribute on the sidenote. Hovering over the text or the sidenote highlights both so it’s easier to know what text references the note (and which one is the note linked to that sentence).
If the screen isn’t big enough (smaller than 1280px), then it hides the notes. In order to make them visible it’s necessary to click or tap on the underlined text, then it shows the note below it, which can be hidden
(sidenote:
If you look below on the HTML markup, you'll notice there's an <input> tag with type="checkbox" on there, this what's used in order to show/hide the notes on click.
)
on the text.
Another thing is that, for screen readers, the side note should render with just after the text with a “(sidenote: the note)” after the text, which should help understand the context of it.
Overall, I’m pretty happy with the result.
Implementation#
Here’s the gist of it: I’ve created a new shortcode called sidenote.html on my layouts/shortcodes folder that looks like the following:
<span class="sidenote">
<label class="sidenote-label" for="{{ .Get 1 }}">{{ .Get 2 }}</label>
<input class="sidenote-checkbox" type="checkbox" id="{{ .Get 1 }}">
<small class="sidenote-content sidenote-{{ .Get 0 }}">
<span class="sidenote-content-delimiter"> (sidenote: </span>
{{ .Inner }}
<span class="sidenote-content-delimiter">)</span>
</small>
</span>
Then, with this little SCSS file I style them for both, big and small screens:
/**
* Side notes styling
*/
$container-width: 30rem;
$sidenote-width: 16rem;
$sidenote-offset: 1.5rem;
$border-width: 0.15rem;
$border-width-mobile: 0.13rem;
.sidenote {
.sidenote-checkbox {
display: none;
}
.sidenote-label {
border-bottom: 0.075rem dashed $primary;
}
.sidenote-content {
display: block;
position: absolute;
width: $sidenote-width;
box-sizing: border-box;
margin-top: -1.5em;
border: 0.075rem solid $greyTableBorder;
border-radius: 0.2rem;
padding: 1rem;
&.sidenote-left {
left: 0;
margin-left: 10vw;
}
&.sidenote-right {
right: 0;
margin-right: 4vw;
}
&-delimiter {
display: none;
}
}
&:hover {
.sidenote-label {
background-color: rgba($primary, 0.1);
color: $black;
}
.sidenote-content {
border: $border-width dashed $primary;
}
}
}
@media screen and (max-width: $xl) {
.sidenote {
.sidenote-content {
position: static;
margin-top: 10px;
margin-bottom: 10px;
width: 100%;
display: none;
}
&:hover {
.sidenote-content {
border: $border-width-mobile dashed $primary;
}
}
.sidenote-checkbox:checked {
&~ .sidenote-content.sidenote-right, &~ .sidenote-content.sidenote-left {
display: block;
}
}
.sidenote-content.sidenote-left, .sidenote-content.sidenote-right {
margin-left: 0px;
margin-right: 0px;
}
}
}
Thanks#
This implementation did not come out of the blue. I was first inspired by this great blogpost by dade, which in turn, was inspired by a post by Daniel Fedorin. I tried to make it a bit more semantic using <small> element, inspired by this StackOverflow question. What I can assure you is that no LLM was involved on this implementation at all. You can visit the source for this blog at my Gitlab profile.
Hope you like them!