194

position: sticky works on some mobile browsers now, so you can make a menu bar scroll with the page but then stick to the top of the viewport whenever the user scrolls past it.

But what if you want to restyle your sticky menu bar slightly whenever it's currently 'sticking'? eg, you might want the bar to have rounded corners whenever it's scrolling with the page, but then as soon as it sticks to the top of the viewport, you want to get rid of the top rounded corners, and add a little drop shadow underneath it.

Is there any kind of pseudoselector (eg ::stuck) to target elements that have position: sticky and are currently sticking? Or do browser vendors have anything like this in the pipeline? If not, where would I request it?

NB. javascript solutions are not good for this because on mobile you usually only get a single scroll event when the user releases their finger, so JS can't know the exact moment that the scroll threshold was passed.

BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
callum
  • 34,206
  • 35
  • 106
  • 163

6 Answers6

161

There is currently no selector that is being proposed for elements that are currently 'stuck'. The Postioned Layout module where position: sticky is defined does not mention any such selector either.

Feature requests for CSS can be posted to the www-style mailing list. I believe a :stuck pseudo-class makes more sense than a ::stuck pseudo-element, since you're looking to target the elements themselves while they are in that state. In fact, a :stuck pseudo-class was discussed some time ago; the main complication, it was found, is one that plagues just about any proposed selector that attempts to match based on a rendered or computed style: circular dependencies.

In the case of a :stuck pseudo-class, the simplest case of circularity would occur with the following CSS:

:stuck { position: static; /* Or anything other than sticky/fixed */ }
:not(:stuck) { position: sticky; /* Or fixed */ }

And there could be many more edge cases that would be difficult to address.

While it's generally agreed upon that having selectors that match based on certain layout states would be nice, unfortunately major limitations exist that make these non-trivial to implement. I wouldn't hold my breath for a pure CSS solution to this problem anytime soon.

BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
  • 1
    Unfortunately @BoltClock is right, it won't be native for a long long time. Example hacks around these could be found at: yahoo mail (scroll a mail's content, they have a nice trick) and google dashboard (uses absolute shadow element). – oori Sep 16 '14 at 19:17
  • 28
    That's a shame. I was looking for a solution to this problem too. Wouldn't it be fairly easy to simply introduce a rule that says `position` properties on a `:stuck` selector should be ignored? (a rule for browser vendors I mean, similar to rules about how `left` takes precedence over `right` etc)) – powerbuoy Apr 18 '16 at 13:01
  • 8
    It isn't just position... imagine a `:stuck` that changes the `top` value from `0` to `300px`, then scroll down `150px`... should it stick or not? Or think about an element with `position: sticky` and `bottom: 0` where the `:stuck` maybe changes `font-size` and therefore the elements size (therefore changing the moment in which it should stick)... – Roman Feb 15 '17 at 11:18
  • 3
    See https://github.com/w3c/csswg-drafts/issues/1660 where the proposal is to have JS events to know when something becomes stuck/unstuck. That should not have the issues that a pseudo-selector introduces. – Ruben Aug 25 '17 at 07:26
  • @Ruben: I'm all for that. – BoltClock Aug 25 '17 at 07:27
  • 59
    I believe the same circular problems can be made with many already existing pseudo-classes (e.g. :hover changing width and :not(:hover) changing back again). I would love :stuck pseudo-class and think that the developer should be responsible for not having the circular issues in his code. – Marek Lisý Sep 10 '17 at 15:56
  • @Marek Lisý: Yes, the reasoning given by browser vendors is that they don't want to make the same mistake. I agree that the author should be responsible, but vendors do still have to guard against author mistakes. – BoltClock Sep 10 '17 at 16:05
  • 30
    Well... I don't really understand this as mistake - it's like saying `while` cycle is badly designed because it allows endless loop :) However thanks for clearing this up ;) – Marek Lisý Sep 10 '17 at 18:22
  • 2
    @LazarLjubenović Here is a blog post with a hack that you can use in the interim: https://developers.google.com/web/updates/2017/09/sticky-headers – Ruben Mar 20 '18 at 11:08
  • 1
    I highly advise against the hack above. The global support for IntersectionObserver is low. If you don't have nested scrolling, you're better off using getClientBoundingRect() and scroll listening. – Seph Reed Sep 29 '18 at 01:02
  • 3
    if ie4 could support `:hover{display:none;}` i'm sure modern browsers will not explode with `:stuck{position:static;}` – oriadam Mar 06 '19 at 13:36
  • @oriadam: Have you actually seen what :hover{display:none;} looks like? On most browsers elements just flicker in and out of existence as fast as your display can refresh. And the rest of the layout gets affected as it happens. I don't think browsers want to introduce *more* situations like that. – BoltClock Mar 16 '19 at 05:19
  • 2
    @BoltClock Yes, it looks buggy. The possibility to create a buggy behavior with an elaborated technique is not a reason to disable a (much needed) feature all together. For example, being able to enter `
    ` (instead of `
  • `) inside `
      ` is not a reason to discard lists all together, is it?
– oriadam Mar 17 '19 at 12:37
  • @oriadam: Bad markup and cyclic dependencies in CSS are two different classes of problems entirely. – BoltClock Mar 20 '19 at 03:16
  • 2
    @BoltClock It's just a parable. Here's another one - should we cancel loops in JS because one can do endless loop? The element would flicker like crazy when doing `:stuck{position:static}` - so be it. It shouldn't happen anyway, people just want the :stuck to set box-shadow or change some element by checking `.is(':stuck')` on `scroll` event. – oriadam Mar 20 '19 at 09:29
  • 2
    The endless loop example that both @oriadam and MarekLisý have mentioned seems like a good comparison to me. I don't understand why CSS needs to prevent devs from writing bad code. Is there some technical reason that makes it either impossible or prohibitively expensive to implement such a feature? The fact that devs might make mistakes with it surely can't be the reason. – dev_willis Sep 07 '19 at 17:13
  • 6
    can `:stuck` just ignore positional properties? mostly it will just be used to add a freakin shadow anyway... – oriadam Sep 09 '19 at 07:28
  • I've added an [answer below](https://stackoverflow.com/a/66595824/1528315), which includes a pure CSS hack that simulates `::stuck`. – Tom Anthony Mar 12 '21 at 07:23
  • So they still didn't do it in 2022? maan.. It should be so simple. And i agree with those saying these kind of problems can be found with very many programming features. – LuckyLuke Skywalker Jul 25 '22 at 10:55
  • There are lots of cases where CSS can have circularity, like where :hover will move something, causing it to no longer be hovered, etc. That's fine: it causes visual glitches and the developer fixes it. It's not a convincing reason to not have important, obvious features, like when you want a button to only appear on the sticky header and not repeat in every visible header. – Glenn Maynard Oct 14 '22 at 21:12
  • How hard can it be: `if :stuck then ignore(list of attributes)`. Definitions of *flexbox item attributes* get ignored when a parent element isn't a *flexbox container*, nothing new there. Not being able to check the current state of an element (`stuck`, `transformed`, `inviewport`, to name a few) in CSS is a HUGE omission. Besides that, I'd say: let developers worry about circular calls, not the specs. They've been doing that since 'programming' was invented and gotten wiser in the process. – Rene van der Lende Mar 01 '23 at 15:17