From c49a6b4ad45d9aa452a2c18637cfe3fa514db792 Mon Sep 17 00:00:00 2001 From: Jake Lazaroff Date: Sun, 15 Dec 2024 21:56:14 -0500 Subject: [PATCH] Anchor scroll position to the bottom --- css/anchor-scroll-position-to-the-bottom.md | 44 +++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 css/anchor-scroll-position-to-the-bottom.md diff --git a/css/anchor-scroll-position-to-the-bottom.md b/css/anchor-scroll-position-to-the-bottom.md new file mode 100644 index 0000000..3870349 --- /dev/null +++ b/css/anchor-scroll-position-to-the-bottom.md @@ -0,0 +1,44 @@ +# Anchor scroll position to the bottom + +Recently, I was building a "timeline" for an explorable animation, in which new elements would be added below. As elements were added, I wanted the scroll position anchored to the bottom of the timeline, as it would be in a chat app. + +Specifically: + +- The first element should start at the top. +- New elements should enter the timeline below any existing elements. +- If the container is scrolled to the bottom, it should remain scrolled to the bottom to reveal new elements as they're added. +- But if the container is scrolled _up_, the scroll position should remain the same such that new elements are added below the fold. + +Initially, I thought I might have to mess around with [`MutationObserver`](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver), but I found [this StackOverflow answer](https://stackoverflow.com/a/44051405) with a neat CSS-only solution. + +The answer used `flex-direction: column-reverse`. That mostly works, with two caveats: + +1. Elements start at the bottom, rather than the top. +2. More seriously, the markup needs to be in reverse order. + +Luckily, a commenter pointed out a trick to fix both of those: wrap the list in another element, and apply the flexbox properties to the _wrapper_. Then, to force the list to the top of the wrapper, add a shim before it in the markup (which places it below it in the wrapper's `column-reverse` flexbox flow). + +All in all, the markup would look something like this: + +```html +
+
+ +
+``` + +And the CSS would look like this: + +```css +.wrapper { + display: flex; + flex-direction: column-reverse; + overflow: auto; +} + +.shim { + flex: 1; +} +```