Sidenotes using only CSS
— Kaushal ModiThrough the Mastodon-verse, one day I somehow landed on the amazing website https://takeonrules.com/ by Jeremy Friesen and I got motivated to learn about sidenotes once again.
This post describes my fresh attempt at getting the sidenotes to work.
This is a post in the “Sidenotes” series.
2022-02-05 | Sidenotes using ox-hugo |
2022-02-03 | Sidenotes using only CSS |
I had dabbled into sidenotes CSS about three years back when I came across this blog post by Frans de Jonge, but that attempt just stayed in a git branch and never panned out. This time, I was more determined You need that kind of determination when you are working with CSS 😄 and I got to work by looking online for resources on “sidenotes using CSS”, and my first stop was Kenneth Friedman’s blog post on Marginal Notes.
I liked how the author introduced the basic steps for implementing
marginal notes—that you need to (i) restrict the width of the body
text so that you can fix the sidenotes, (ii) put the notes in a
special tag like <aside>
, and (iii) add CSS
to push the <aside>
tag content outside of the body text.
I really liked it because point (i) was already implemented on this website.
I implemented the later two points using the examples on that blog post, examples from few more blog posts and then a bit more of fiddling with CSS on my own.
HTML elements for sidenotes #
Regarding point (ii) above, I later realized that using the <aside>
tag was a wrong choice for sidenotes. Hugo (or rather its Markdown
parser Goldmark) auto-wraps these tags in <p>
and so we get forced
paragraph breaks around them.
That problem did not show up immediately. But once I started to get
the CSS sidenote counters
sidenote counters allow you to easily find the sidenotes
corresponding to the those counter numbers referenced in the body
text. This is really helpful when you have a lot of sidenotes bunched
together.
to work, I saw that the reference counter numbers in the main text
would always jump to the next paragraph! After few minutes .. OK
.. after a lot more minutes, after reviewing the generated HTML, and
comparing with the CSS seen on various sites, I realized that the
<aside>
tag was the culprit!
Later, I find this another blog post which confirmed what I concluded above:
Markdown rendering generates
<p>
tags. According the to spec,<p>
tags cannot have a block element inside them. When you try to put a block element, such as<div>
inside<p>
, the browser will automatically close the<p>
tag, breaking the rest of the page. So, even though conceptually (and visually) the content of the sidenote is a block, it has to be inside an inline element.
The solution was to use an inline HTML element <small>
or
<span>
for the sidenote content.
<span class="sidenote-number">
<small class="sidenote">
sidenote content
</small>
</span>
The sidenote element that’s referenced few times in this post is
the <small>
HTML element with sidenote
class.
Basic CSS #
Now to point (iii) from Kenneth’s blog ..
Here are my some key takeaways from his blog post:
- Use
float: right;
I usedfloat: left;
because I have the Table of Contents in the right margin. I am going down the untrodden path of putting sidenotes in the left margin. to move the sidenote content to stick to the right side of its parent HTML element. - Use
width: 20vw;
“1vw” = 1% of the width of the viewport, and “viewport” is the browser window size. to limit the width of the sidenotes in the margin. We don’t want the sidenotes to overflow into the body text. - Use
margin-right: -22vw;
I usedmargin-left
instead. to shift the whole sidenotes containing HTML element to outside the body. - And finally, do not use the
<aside>
HTML element to contain the sidenote content—Use an inline element like<small>
instead.
Now I’ll dive into the details of the CSS code. Please bear with me because I am not a web developer. These notes are mainly to document the CSS for myself and to share what I learned. So I would welcome any suggestions and corrections.
Sidenote CSS #
This is the basic CSS that puts the sidenote element in the margin to the left of its container element.
Line 2 : Sidenote content font size is set to be slighter smaller than the default body font size.
Line 3 : The
position
specified later usingtop
is relative to the position of the element.Line 6 : For this website, when the browser window is wider than 1400px, it’s considered as wide viewport. The sidenotes are shown in the margin only for wide viewports.
Line 8 : The whole sidenote element is floated to the left of the parent container.
Line 9 : This is necessary to prevent adjacent sidenotes from overlapping. This blog post puts it nicely:
If an element can fit in the horizontal space next to the floated elements, it will. Unless you apply the
clear
property to that element in the same direction as the float. Then the element will move below the floated elements.Line 10 : The
float
moves the sidenote element to the left most side of the container. But the margin is still further left to that container’s left border. So themargin-left: -<val>;
shifts the sidenote element<val>
units further left to the container’s left border.Line 11 : As the sidenote is floating in the left margin, I wanted the text to the aligned towards Towards the right ⇶ in wide viewport, but it’s left-aligned in narrow viewport as you’ll see in the CSS snippet for narrow viewport. the body text.
Line 14 : The
width
limits the width of the “sidenotes column” that gets created in the left margin.Line 15 : The
margin_top: 1rem;
is just an embellishment tweak that inserts a 1rem space between adjacent sidenotes if they happen to get packed too close vertically.
CSS for mobile view or narrow viewport #
On a narrow viewport like a phone, we cannot afford to display a wide margin just for showing the sidenotes. So I interleave the sidenotes within the body, but with some indentation on the left (line 9 below).
As the sidenotes are within the body, they are still floated to the left, but now the text is aligned to the left instead of right. The width is set to 100% so that the text following the sidenote gets pushed to below it. This part feels like a hack. So if someone can suggest a canonical way to deal with this, please let me know.
Sidenote Counter CSS #
The sidenote counters are implemented using just CSS. Thanks to this codepen by a user dredmorbius and the CSS on takeonrules.com!
Let’s look at the sidenote HTML once again, but this time with some annotation to help understand how the counter number placement works in the body text and next to the sidenote in the margin.
<span class="sidenote-number">❶.sidenote-number INCREMENT COUNTER
<small class="sidenote">❷.sidenote::before COUNTER IN MARGIN
sidenote content
</small>❸.sidenote-number::after REF COUNTER IN BODY
</span>
The sidenote counters need to be reset in the body
element so that
they always begin from 1 on each page.
From the above annotated HTML, ❶ is the .sidenote-number
element
that wraps both of the sidenote counter locations: one in the body
which acts as sidenote reference, and another in the margin next to
the sidenote. So the counter is incremented only once at each
.sidenote-number
element.
❷ is the point where the .sidenote::before
CSS rule will render the
counter number before the sidenote content. As the .sidenote
element is pushed into the margin, this counter number will also be
pushed out along with the sidenote.
And finally, ❸ is the point that still remains at its original place
within the main body. This is where the refernce counter value gets
rendered. The .sidenote-number::after
CSS rule is responsible for
this.
|
|
This final CSS snippet is responsible for highlighting the corresponding sidenote in the margin when mouse is hovered over a sidenote reference counter number in the body.
@media (min-width: 1400px) {
/* Highlight the sidenote when mouse hovers on the sidenote number in body. */
.sidenote-number:hover .sidenote {
background-color: yellow;
}
}
Things to improve #
While floating the sidenotes to the left moves them into the left margin, that aligns the left border of all the sidenotes to the left side of the page.
What I really wanted to do is to:
- Move the sidenotes into the left margin.
- Align the right border of all the sidenotes in a straight line with the left border of the body text.1
Conclusion #
That said, I am quite happy with the way the sidenotes and the counters turned out.
More References #
Apart from the references already linked in this post, here are few other references for creating sidenotes using CSS that I came across during my research:
I already tried changing
float: left;
tofloat: right;
andmargin-left: -23vw;
tomargin-right: 50vw;
but that has an undesirable effect what I don’t understand why—Now the sidenotes occupy the entire vertical space, even the part in the body. ↩︎