diff --git a/src/routes/_posts/sidenotes.svx b/src/routes/_posts/sidenotes.svx index c74ba39..8cb6265 100644 --- a/src/routes/_posts/sidenotes.svx +++ b/src/routes/_posts/sidenotes.svx @@ -25,7 +25,7 @@ draft: true .sidenote-absolute { position: absolute; - left: calc(50vw + var(--content-width) / 2 + 1rem); + left: calc(50% + var(--content-width) / 2 + 1rem); max-width: 12rem; font-size: 0.75rem; } @@ -77,18 +77,33 @@ My first approach was something like this: ```css .sidenote { position: absolute; - /* 50vw takes us to the midpoint of the page, + /* 50% takes us to the midpoint of the page, half of content-width gets out out to the gutter, and the extra 1rem gives us some breathing room. */ - left: calc(50vw + var(--content-width) / 2 + 1rem); + left: calc(50% + var(--content-width) / 2 + 1rem); max-width: 12rem; font-size: 0.75rem; } ``` -And it worked! Sort of. Here's an example.My initial take on sidenotes. Seems to be working, right? Unfortunately it has a couple of flaws. For one, it will overflow the screen as soon as the viewport gets too narow, which is easy enough to solve (just a matter of a sufficiently complex `calc()` expression) but definitely needs doing. More importantly, however, there's no facility for dealing with overlaps. So if you have multiple sidenotes\*Like this one. too close\*And this one, which I've moved down just a smidge to make the overlap more apparent. together, they will overlap because absolute positioning Just Doesn't Care. +And it worked! Sort of. Here's an example.My initial take on sidenotes. Seems to be working, right? Unfortunately it has a couple of flaws. For one, it will overflow the screen as soon as the viewport gets too narow, which is easy enough to solve (just a matter of a sufficiently complex `calc()` expression) but definitely needs doing. More importantly, however, there's no facility for dealing with overlaps. So if you have multiple sidenotesLike this one.And this one, which I've moved down just a smidge to make the overlap more apparent. too close together, they will overlap because absolute positioning Just Doesn't Care. +Obviously, the blunt-instrument solution to this is Javascript, but it's less than ideal for a variety of reasons: +* I wanted to write this as a Svelte component, which means that's the obvious place to put this logic. But because there are many instances of the component and I only want to run the collision-detection logic once, it has to be coordinated across multiple instances of the same component, which is always painful. +* Because we have to wait for the sidenote elements to _have_ concrete positions before we can detect whether they collide, we can't do this until they are mounted (i.e. inserted into the DOM). I was concerned that this would cause [FOUC](https://en.wikipedia.org/wiki/Flash_of_unstyled_content)-like problems, although in retrospect I don't actually recall it happening.Possibly it was mitigated by the way Svelte batches DOM updates.However, since I was always planning on static-rendering the site and letting SvelteKit do client-side hydration on page load, I don't think the possibility could ever be ruled out entirely. +* Anything that triggered a reflow would cause sidenote positions to get positionally out of sync with their references, and might even cause collisions again. [There are a lot of things that can cause a reflow](https://gist.github.com/paulirish/5d52fb081b3570c81e3a), and I'd have to listen to all of them if I wanted this to be a fully general solution. Sure, you could argue that since it's my site, I could just be aware of this problem and avoid using reflow-causing events where possible--but I wanted the freedom to be able to add as much interactivity as I felt like to any given blog post without having to worry. -https://scripter.co/sidenotes-using-only-css/ +None of these problems are _completely_ inaddressible, but it was all going to be very fiddly to fix properly, so I decided to do a bit more research before throwing in the towel. And boy am I glad that I did, because it turns out that with enough... + +## CSS Wizardry + +...anything is possible. + +Eventually I ran across [this post](https://scripter.co/sidenotes-using-only-css/), which describes a shockingly elegant solution to the problem with very few downsides.It's worth noting that this same approach seems to be used by [Tufte CSS](https://edwardtufte.github.io/tufte-css/), which I had looked at previously but had failed to comprehend, possibly because it doesn't really go into detail about its sidenote mechanism. The basic idea is extremely straightforward: + +1. Give your sidenotes a float, so that they are removed from the regular document flow _but_ (and this is crucual) _other text still makes space for them._ +2. Give them a fixed width, and then: +3. Give them a negative margin equal to the max-width, so that they are pulled out of the body of the text and hang out in the gutter. +4. Lastly, give them a `clear` value so that when multiple sidenotes try to occupy the same space the later ones get pushed down below the earlier ones. I'll be honest: this is the bit that I understand the least. I know the basic idea of what `clear` does--it forces the parent of a floated element to expand so that it contains it--but I don't know why it causes multiple floated elements to stack on top of each other like this.