Solved by CSS Scroll-Driven Animations: hide a header when scrolling down, show it again when scrolling up. (original) (raw)

https://www.bram.us/wordpress/wp-content/uploads/2024/09/hide-on-scroll-down-show-on-scroll-up.mp4

Recording of Fabrizio’s demo

By adding a long transition-delay to a CSS property under certain conditions (which you can do using a Style Query), you can persist its value after the condition no longer applies.

~

Detecting the Scroll-Direction with CSS Scroll-Driven Animations

One of the demos that I built as part of the “Solved by CSS Scroll-Driven Animations: Style an element based on the active Scroll Direction and Scroll Speed” article is a header element that hides itself on scroll.

Here’s the demo I’m talking about: as you scroll up or down, the header hides itself. When idling, it comes back into view. Check it out using a Chromium-based browser, as those – at the time of writing – are the only browsers to support Scroll-Driven Animations.

See the Pen CSS scroll-direction detection with Scroll-Driven Animations with moving header by Bramus (@bramus)
on CodePen.

In the code of that demo there are few CSS variables that are either 0 or 1 when scrolling – or not-scrolling – when scrolling in a certain direction. The CSS looks like this:

--when-scrolling: abs(var(--scroll-direction));
--when-not-scrolling: abs(var(--when-scrolling) - 1);

--when-scrolling-up: min(abs(var(--scroll-direction) - abs(var(--scroll-direction))), 1);
--when-scrolling-down: min(var(--scroll-direction) + abs(var(--scroll-direction)), 1);

--when-scrolling-down-or-when-not-scrolling: clamp(0, var(--scroll-direction) + 1, 1);
--when-scrolling-up-or-when-not-scrolling: clamp(0, abs(var(--scroll-direction) - 1), 1);

💁‍♂️ If you want to know exactly how it works, go check out episode 9 of the free video course “Unleash the Power of Scroll-Driven Animations” I made, which teaches you all there is to know about Scroll-Driven Animations. The episode is also right here:

~

The transition-delay trick

As I had noted in the article, these variables are fleeting. From the moment you stop scrolling, all those variables – except --when-not-scrolling – become 0 again. Therefore, the header in the example will reveal itself again once you stop scrolling. A better experience would be to hide the header when scrolling down and to keep it that way until the moment you scroll up again. However, I didn’t find a solution to do that back then.

Fast forward to a few months later. While at CSS Day 2024, Schepp shared that he found way to make those custom properties “sticky”. His trick? Adding a long transition-duration to the properties when scrolling in a certain direction.

In the following snippet, the transition is stalled indefinitely when idling. That way, the --scroll-* custom properties will retain their value until you start scrolling again.

@container style(--scroll-direction: 0) {
   header {
      transition-delay: calc(infinity * 1s);  
   }
}

~

Putting it all together

Unfortunately I hadn’t found the time to actively use Schepp’s suggestion in the hiding header demo ever since we discussed it (but I did use it for my @starting-style feature detection technique).

Fast forward to just last week, and Fabrizio Calderan reached out on X to share his “Hide on Scroll Down, Show on Scroll Up Header” CodePen

See the Pen Hide on Scroll Down, Show on Scroll Up Header by Fabrizio Calderan (@fcalderan)
on CodePen.

Fabrizio came to creating the same trick Schepp had suggested to me, by relying on a long transition-behavior which he sets in a Style Query:

@container style(--scroll-direction: 0) {
   /* Scroll is idle, so we keep the current header position by setting the transition-delay to infinity */
   header {
      transition-delay: calc(infinity * 1s);  
   }
}


@container style(not (--scroll-direction: 0)) {
   /* page is scrolling: if needed, the animation of the header should run immediately */
   header {
      transition-delay: 0s;  
   }
}

@container style(--scroll-direction: -1) {
   /* Scrolling up, so we must reveal the header */
   header {
      --translate: 0;
   }
}

@container style(--scroll-direction: 1) { 
   /* Scrolling down, so we must hide the header */
   header {
      --translate: -100%;
   }
}

Nice one, Fabrizio!

When trying it out, you’ll notice it still is not 100% perfect though, as you can end up in situation where the header remains hidden when starting a scroll down immediately followed by a scroll up. This confirms to me that there still is a need to have the scroll-direction be exposed by the browser itself, instead of needing to rely on a hack powered by Scroll-Driven Animations. The current line of thinking is to use a Scroll-State Style Query for this.

~

Spread the word

Feel free to repost one of the posts from social media to give them more reach, or link to this post from your own blog.

📝 Solved by CSS Scroll-Driven Animations: hide a header when scrolling down, show it again when scrolling up

By adding a long transition-delay to a CSS property under certain conditions (with a Style Query), you can persist its valuehttps://t.co/dzFlc9Jvmt

Demo by @fcalderan pic.twitter.com/glDlpcCSIJ

— Bram.us (by @bramus) (@bramusblog) September 29, 2024

~