📌 Sidenotes with CSS Anchor Positioning
Sidenotes without JavaScript: typed attr(), anchor(), max() and a fallback for narrow screens.

Vincent Bernat used CSS Anchor Positioning to create sidenotes that sit in the page margins exactly opposite the relevant passage of text, without a single line of JavaScript.
💡 How does it work?
The markup uses ordinary HTML elements and data attributes:
<!-- Знак сноски в тексте -->
<sup data-anchor="note-1">1</sup>
<!-- Текст сноски (сразу под абзацем) -->
<aside role="note" data-anchor="note-1">1. Текст заметки...</aside>
Connecting them with attr() and CSS Custom Properties
The CSS uses typed attr() (with the type <dashed-ident>), so the value of data-anchor becomes an anchor name directly, without hardcoding it in the styles:
sup[data-anchor] {
/* Динамически создаем имя якоря из дата-атрибута */
anchor-name: attr(data-anchor type(<dashed-ident>));
}
aside[role="note"][data-anchor] {
/* Привязываем сноску к соответствующему якорю */
position-anchor: attr(data-anchor type(<dashed-ident>));
}
Positioning on wide screens
On desktop, the note moves into the right margin of the page. But the key is vertical alignment with anchor() and preventing notes from overlapping one another (max()):
@media (min-width: 60rem) {
aside[role="note"] {
position: absolute;
/* Выносим в правое поле */
left: calc(100% + 2rem);
width: 15rem;
/* Делаем саму сноску якорем для ДРУГИХ сносок */
anchor-name: --sidenote;
/* Выбираем максимальную высоту:
либо верх знака сноски anchor(top),
либо низ предыдущей сноски anchor(--sidenote bottom) + отступ */
top: max(anchor(top), anchor(--sidenote bottom, 0px) + 1rlh);
}
}
🧠 What’s the trick with max()?
If two footnote markers are too close together in one paragraph, the second note could overlap the first. With anchor(--sidenote bottom), CSS sees the bottom edge of the previous sidenote. The max() function compares the positions: if the footnote marker is below the previous note, it uses the marker’s position; if the marker is above it, the note is “pushed away” from the previous one and moves lower.
🛡 Fallback for narrow screens and older browsers
Without the media query and support for anchor positioning (or on mobile), the aside[role="note"] elements remain in normal block flow immediately after their paragraph, styled with a slightly more muted color and a smaller font. The markup reads naturally and looks good on any device!