Skip to content

[css-position] Events for stickiness changes #1660

Open

Description

@cvrebert

https://drafts.csswg.org/css-position/#sticky-pos

Since the suggestion in #1656 for a :stuck pseudo-class is not feasible, the next best alternative would be for browsers to fire events (e.g. stuck, unstuck), similar to those of CSS Transitions, whenever a position: sticky; element changes its stuckedness. Then the same styling abilities become possible at the cost of a teeny bit of JS and a teeny associated processing delay:

.some-class.is-stuck {
  /* cool stuck-specific styles here */
}
myStickyElement.addEventListener('stuck', function () {
  this.classList.add('is-stuck');
});
myStickyElement.addEventListener('unstuck', function () {
  this.classList.remove('is-stuck');
});

For robustness, the relevant event also needs to be fired when the element changes between the posititon: <anything but sticky> and (position:sticky-and-currently-stuck) states.

Activity

  1. jhpratt commented on Jul 29, 2017

    @jhpratt

    Agreed 100%. If a pseudoclass isn't feasible (and I agree it isn't for the reason Tab stated), there should still be some way of knowing.

  2. FremyCompany commented on Aug 31, 2017

    @FremyCompany
    Contributor

    Couldn't you use an IntersectionObserver, narrowing your viewport to the area where the element will end up stuck (either top or bottom of the screen)?

  3. atjn commented on Sep 14, 2017

    @atjn

    I tried, and was not able to use IntersectionObserver to fix this. It doesn't seem to work with sticky elements when they are sticking to the top of the viewport. Not sure if this is a bug or not.

  4. FremyCompany commented on Sep 14, 2017

    @FremyCompany
    Contributor

    Seems like a bug. Do you have a test case? That would be super valuable!

  5. atjn commented on Sep 14, 2017

    @atjn

    Unfortunately, i deleted the buggy code. So i tried to replicate the issue in a simpler setup, but then it actually worked! So maybe the bug is more specific than I thought, or maybe I simply made an error in my original code. I am sorry that I can't be of more help than that.

    The good part about this is that we can use it. And I am actually using it on a new small project. It's a slightly more advanced implementation, but if anyone wants to use it in their projects, they are very welcome to take a look at it here: [broken link].
    Note that the function only works when the page is viewed on a real/emulated mobile phone.
    Also note that i am still working on this project for a few days to come, so the site is subject to changes or breaking, but i will not be removing the IntersectionObserver feature.

  6. FremyCompany commented on Sep 15, 2017

    @FremyCompany
    Contributor

    Great to see that it's actually working for you!
    FWIW I just tried this in Edge Insider Preview with position:sticky support and it worked like a charm.

  7. FremyCompany commented on Sep 15, 2017

    @FremyCompany
    Contributor

    Agenda+ to close as NoChange if no one else has a strong opinion on this

  8. SebastianZ commented on Sep 20, 2017

    @SebastianZ
    Contributor

    While the IntersectionObserver solution is working, it looks a bit like a hack in regard of the rootMargin value and is much more verbose than using events.

    Sebastian

  9. css-meeting-bot commented on Sep 20, 2017

    @css-meeting-bot
    Member

    The Working Group just discussed Events for stickiness changes, and agreed to the following resolutions:

    • RESOLVED: Close issue 1660 no change.
    The full IRC log of that discussion <dael> Topic: Events for stickiness changes
    <dael> github: https://github.com//issues/1660
    <dael> Rossen_: Summary, issue is someone asked if we can have an event to be able to know when the element goes into a stuck state and if it transitions to unstuck.
    <dael> Rossen_: There were a few suggestions given, fremy pointed out if you use intersection observer everything works. After a little while people confirmed this is the case. They proposed to close no change.
    <dael> Rossen_: I want to hear if you agree with this.
    <dael> smfr: I agree
    <dael> Rossen_: Objections to close, no change?
    <dael> RESOLVED: Close issue 1660 no change.
  10. SebastianZ commented on Sep 21, 2017

    @SebastianZ
    Contributor

    Unfortunately my comment was not addressed in the discussion. Could this be reconsidered?

    Sebastian

  11. atjn commented on Sep 22, 2017

    @atjn

    I completely agree with @SebastianZ that using the IntersectionObserver is a hack, that would never work as well as a native solution.

    And since this issue is very directly linked to any native sticky headline, i think something should be done to make a more native solution.

  12. kizu commented on Sep 22, 2017

    @kizu
    Member

    I would say that I'm also for the native stickiness events and against using hacks or any non-trivial code for that.

    More than that, I also totally disagree with any arguments against the :stuck in CSS, but well, it seems that there is no way devs would persuade spec-writers to add it.

  13. 8 remaining items

  14. hunboy commented on Jan 22, 2018

    @hunboy

    I've cloned the most common usage of sticky header in my own way. I had to use 2 indicators with 2 Observer. Summary: I still vote to the :stuck pseudo, because this code is not my favorite, however works:

    https://jsfiddle.net/utasir/92L8L85q/12/

    If someone knows how to make it simpler, I'll appreciate that.

    Actually my problem with my code if it is against the separation theory of style and html structure.
    So I'm still looking for a solution without extra html elements.

    I've reduced the code to 1 indicator only, but now no reverse animation effect. I think this the max we can do for it with intersectionObserver. Other stuff is: position sticky element has reserved space int he flowed content, so resize made a layout jump. Workaround adding a margin-bottom to :stuck styled header.

    https://jsfiddle.net/utasir/92L8L85q/17/

  15. geoken commented on Jan 22, 2018

    @geoken

    So to summarize;

    1. There is an element and the browser will use some logic to set it to 1 of 2 states.
    2. Letting the browser tell us when the state has changed or what it is, is unfeasible
    3. Letting us create pseudo elements for no other purpose than essentially running hit detection code to try and infer the state of [css-syntax] Add a Previous Version link to the CR. #1 is feasible?

    Why is #2 undesirable vs. having us infer that same thing in an indirect way?

  16. rubenlg commented on Mar 20, 2018

    @rubenlg

    Sure you can use JS+DOM hacks (based on IntersectionObserver) to figure out when something started to stuck. The exact same argument could be given for position:sticky itself. Plenty of websites implement(ed) it with JS+DOM hacks. And yet, browsers decided to support position:sticky natively to make it more convenient, less hacky, and more robust.

    Does anyone have any better argument against the proposal in this issue than "it can be done with JS+DOM hacks"? Or at least one that is consistent with the decision to implement position:sticky in the first place?

  17. upsuper commented on Mar 20, 2018

    @upsuper
    Member

    There is a comprehensive explanation about why :stuck is not feasible in CSSWG's FAQ: https://wiki.csswg.org/faq#selectors-that-depend-on-layout

  18. upsuper commented on Mar 20, 2018

    @upsuper
    Member

    It seems people have been aware of the FAQ item. Sorry for the noise. For the proposal in the issue itself, the event approach, I don't think that's infeasible.

  19. upsuper commented on Mar 20, 2018

    @upsuper
    Member

    Thought about it a bit more, I guess even if we want something more convenient to get notified from stuck / unstuck, that's probably better also be an observer-like thing, rather than an event. I don't think we want to add more event into the layout pipeline, since event needs to be synchronous, which makes it easier to slow down pages, and it doesn't seem to me that the usecase here requires being synchronous. So using an asynchronous observer mechanism should be preferred over events.

  20. upsuper commented on Mar 20, 2018

    @upsuper
    Member

    On the other hand, it seems adding one observer type for each thing we want to listen to feels heavier than adding an event, where we can just share the whole mechanism.

    Maybe we should invent a new LayoutObserver-ish thing and design an API similar to the event listener, but make it async. That way we can add new observing type easily. Some of the existing events can probably also be added there for performance etc. (Maybe there has been some idea like this proposed in WICG?)

  21. kizu commented on Mar 20, 2018

    @kizu
    Member

    Re :stuck: btw, I don't find the wiki FAQ answer in any way sufficient. The toggle states part should be plain removed, as something that we would never have for similar reasons, and having something that would never matter as an arguments against something else is a circularity issue by itself, haha.

    And I never heard any arguments why white-listing properties can't be used. There is a finite amount of properties that are used in most of the use cases for the :stuck, and almost none of those touch layout in any way. Shadows, background, color etc. — in most cases the design needs for :stuck touches on those.

    Whitelisting some of the properties would be enough for start, and then we could start to think about the proper global solution for any circularity issues.

  22. rubenlg commented on Mar 20, 2018

    @rubenlg

    Thanks for the details @upsuper

    What exactly happens when a layout event fires that slows down pages? Is it that the layout algorithm gets blocked until the event handler completes? I thought that event handlers had to run in tasks within the event loop, independently of the layout code of the browser. Or is this an implementation detail of some particular browser?

  23. klimashkin commented on Jan 7, 2019

    @klimashkin

    I don't really get how does intersectionObserver with rootMargin hack work here http://htx.antonjuulnaber.dk/afsaltningsanlaegget/ ?

    How to read rootMargin: "0px 0px -99% 0px"? What does it mean?
    It doesn't work in my case.

  24. klimashkin commented on Jan 7, 2019

    @klimashkin

    Oh, I think I got it - minus means inwards, shrink bounding rectangle inwards..

    But that doesn't work when sticky element is the very first inside it's root, and it has top: 0.
    Because it doesn't move anywhere on scroll, it becomes sticky immediately, but intention actually to add shadow only after user starts scrolling to show that sticky element has started hovering the following content.

  25. klimashkin commented on Jan 7, 2019

    @klimashkin

    Hack with adding sentinel elements to the top and the bottom of the scrolling root like this one has limitations.
    In certain cases I can't add extra elements inside container and when I can it become not possible to use some pseudo-classes like :first-child for a meaningful content.

    In general this way adds cumbersome code and difficulties for other team member to reason about it.
    So I'm not sure why The Working Group decided that intersectionObserver hack is well enough. It is not in real life.

  26. zipper commented on Feb 26, 2019

    @zipper

    There is a problem with sentinel elements when we use position: sticky for sticking table parts (column, header, ...). In that case, there are actually several problems. Starting with we are unable to add <div> inside table <tr> element, or dealing with unknown column width. I'm unable to solve this without CSS :stuck or similar JS event or intersetion observer. Only solution for me in this case would be scroll events.

  27. tayloraucoin commented on Sep 9, 2019

    @tayloraucoin

    IntersectionObserver is also non-compatible with IE. So any implementation with it will not be backward compatible with the relic browser.

  28. atjn commented on Sep 10, 2019

    @atjn

    @tayloraucoin true, but any new spec also won't be compatible, and IE doesn't have support for the sticky position anyways.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions