question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

"Sub-page" `Sticky` Components

See original GitHub issue

This ticket is specifically for discussion of supporting <Sticky> elements attached to in-document scrollable elements.

As an example of such a case:

<div className="scrollable"><StickyContainer><Sticky>...</Sticky></StickyContainer></div>

There are two ways to interpret the expectation in this case:

  • When <Sticky> is scrolled to the top of the scrollable element, it sticks to the top of the window.
  • When <Sticky> is scrolled to the top of the scrollable element, it sticks to the top of the element.

Let’s leave the first interpretation aside for now, since it’s unlikely to be a useful one. This leaves three cases for us to consider.

  1. Sticking to a scrollable element outside the StickyContainer.
    • This is most similar to the existing behavior.
  2. Sticking to a scrollable element inside the StickyContainer.
  3. Sticking to a scrollable StickyContainer.

Catch 1 (demonstrated here) – scroll events don’t propagate. This implies that the only way to intercept contained scroll events is to subscribe to the scrollable element, which further implies that automagically subscribing to the correct scrollable (non-StickyContainer) element is either expensive, unreliable, or impossible.

Possible Solution 1.A – we can solve this problem by requiring the user to supply a prop identifying the scrollable element to watch, but sharp edge cases abound.

Possible Solution 1.B – we can restrict scrollable elements we’ll respect to StickyContainer instances (or possibly a ScrollableStickyContainer subclass).

Catch 2position: fixed (which is used for all of our low-jank positioning) cannot be contained by scrollable elements. This would require us to implement a separate positioning computation for non-window containers.

Possible Solution 2.A – we can require the scrollable element to have position, and use a position: absolute based position calculation.

Possible Solution 2.B – we can recalculate a screen-based positioning based on the watched element when appropriate.

Catch 3StickyContainers are designed to be nested, so that more deeply nested Sticky elements will stick to one another (a la the timeline example). This is accomplished by StickyContainers subscribing to data from their ancestors about other sticky elements. StickyContainers being used within a scrollable element context MUST NOT inherit that data.

Possible Solution 3.A – we use the presence of the prop identifying the scrollable element as a sentinel for when we should avoid subscribing to ancestor data.

Possible Solution 3.B – we use a ScrollableStickyContainer subclass as the data subscription boundary.


This may not represent a complete list of the known concerns or possible solutions, but it seems like one potential solution for solving the general “sub-page” problem might look like this:

<StickyContainer>
  ...
  <Sticky key="first">
    I listen to `window`
    I stick to `window`
  </Sticky>
  ...
  <StickyContainer>
    ...
    <Sticky key="second">
      I listen to `window`
      I stick to "first"
    </Sticky>
    ...
    <ScrollableStickyContainer key="container">
      <Sticky key="inner">
        I listen to "container"
        I stick to "container"
      </Sticky>
      ...
      <StickyContainer>
        <Sticky key="fourth">
          I listen to "container"
          I stick to "inner"
        </Sticky>
      </StickyContainer>
    </ScrollableStickyContainer>
  </StickyContainer>
</StickyContainer>

To those who are interested in this feature, does this seem like an acceptable solution?

Issue Analytics

  • State:closed
  • Created 7 years ago
  • Reactions:12
  • Comments:8 (3 by maintainers)

github_iconTop GitHub Comments

2reactions
pvandecommented, Jun 3, 2016

I don’t view 1.A and 1.B as wildly incompatible, but I feel like 1.B is easier to explain and understand. The biggest difference between the options is flexibility, but if option 1.B were acceptably flexible, it’s probably preferable.

As far as Catch 2 goes, 2.A is simpler to implement and understand, but again, restricts the styles that can be applied to the scrollable container (specifically, not position: static). 2.B requires us to calculate position based on container scroll and all parent container scrolls and window scrolls … which isn’t terribly fun.

3.A really only works with 1.A, and 3.B really only works with 1.B.

This is far from a polished sample, but I spent a little time this evening hacking to investigate the performance characteristics. This implements a solution around {1,2,3}.B without much error bounds checking, and without completing the “stacking” of Sticky components.

It also differentiates between Sticky and InlineSticky components, which is more about being lazy than an expected implementation.

The biggest takeaway for me is that the implementation isn’t as janky as I’d feared it might be, which is a nice perk. I will likely spend a little more time hacking on this example as time allows…

http://codepen.io/anon/pen/rLVOoE

1reaction
AntonVoltchokcommented, Jul 19, 2016

A little note about the “fixed” issue, a little while we rolled out a simpler version of Sticky and by accident I ran into the fact that you can nest fixed elements in relation to each other not the window with just CSS, when you apply any 3rd transformation on the parent , it’s children are now on a coordinate system based on the parent, so the window width now becomes the parent width, I looked this up to make sure it’s not a bug and turns out the browsers implemented it this way on purpose. So for example:

Window with a small chat box container inside of it, this chat box is position fixed to the bottom right, now let’s say you want to have a navbar fixed to the top of that chat box container, if you do top:0, width 100% , it as expected will be at the top of the window nowhere near the chat box, however if you apply for example a translateY(0) on the chatbox, now the chat navbar instead will assume the “window” is the width of the chatbox , and top:0 now becomes the top of the chatbox. Just something cool I ran into by accident and have been using it situationally since .

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to Make Any Page Element Sticky - YouTube
In this episode of Divi Nation we'll be sharing a handy tip on how to make any Divi page element “ sticky ”....
Read more >
Setting up navigation - Material for MkDocs - GitHub Pages
Material for MkDocs provides a multitude of options to configure the behavior of navigational elements, including tabs and sections, and one of its ......
Read more >
Sticky elements: functionality and accessibility testing
Sticky or fixed elements are parts of a webpage that remain in place when the page is scrolled. They're commonly used to keep...
Read more >
Ask a UXpert: What Is the Best Way to Use Fixed Elements?
Sticky elements can provide a persistent and useful trigger to supplementary information. When done well, they allow for immersive experiences ...
Read more >
Balbooa Help Center: Sticky elements (1/1) - Forums
Sticky elements · 1. Add header to your website · 2. Add class suffix to the home page (page settings), for example "custom-header"...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found