1

I have a two column layout where I want the right column to be position: sticky so it stays in view while scrolling the longer left column.

These are two bootstrap columns, so the first thing I had to do was remove the floats (and instead am using display: inline-block).

This works just fine on its own, or near the top of the DOM of this particular page, but in the rendered location (which, alas, is some 30 or so divs deep...don't ask...) I can't get it to work. Both columns just keep on scrolling.

I know if the parent element has an overflow property other than visible that can break position: sticky but that doesn't seem to be the issue here. Is it that if any parent element up the chain has overflow set that it can break sticky positioning?

I'm just sure what to be looking for in this situation as to determine what is breaking it in this situation. Are there other key things to look out for when it comes to sticky positioning?

EDIT: I reworded my question as it does definitely appear (after further investigation and testing) that the issue is a parent element near the top of the DOM was set to overflow-x: hidden. As this is shared code I'll have to hunt down the reason for that and why it's there.

But...in the interim, is there any known workarounds to this...where one can use an element further down the DOM tree as the containing element for the item positioned sticky?

In the example below, if you remove the overflow from .theproblem the page behaves as I want (right column 'sticks' as you scroll through the page).

.theproblem {
  overflow-x: hidden;
}

.column {
  display: inline-block;
  width: 45%;
  vertical-align: top;
}

.column1 {
  border: 1px solid red;
  height: 1000px;
}

.column2 {
  border: 1px solid green;
  position: sticky;
  top: 1px;
}
<div class="theproblem">
  <div class="columnwrapper">
    <div class="column column1">
      This is column 1 (the tall one)
    </div>
    <div class="column column2">
      This is column 2 (the sticky one)
    </div>
  </div>
</div>

JSBin link

showdev
  • 28,454
  • 37
  • 55
  • 73
DA.
  • 39,848
  • 49
  • 150
  • 213
  • 1
    Yes, I believe an `overflow` value other than "visible" defines a scrolling container. The sticky element sticks to its nearest scrolling container ancestor. For reference, see [this answer](https://stackoverflow.com/a/44929597/924299): "...if you set overflow to hidden on any ancestor of your sticky element, then this ancestor element will be the scrolling container for your sticky element". – showdev Jul 12 '19 at 02:49
  • @showdev yea, that's what I'm finding. Essentially, overflow: hidden anywhere in the DOM above your sticky element "breaks" it. (I realize it's technically working per spec, but essentially breaks the usefulness of this feature) – DA. Jul 12 '19 at 02:56
  • I've found it limiting with certain layouts, too. You might consider posting your specific implementation to see if anyone can find a solution. – showdev Jul 12 '19 at 03:01
  • @showdev good call. Example code added. Thanks! – DA. Jul 12 '19 at 03:09
  • One solution might be to use the [Stickyfill polyfill](https://github.com/wilddeer/stickyfill). Despite the fact that it says it "doesn't work in overflowed blocks" and that "scrolling the ancestor will cause the sticky to stick, scrolling the window will not", it seems to work. Be sure to "[f]orce-enable the polyfill, even if the browser supports `position: sticky` natively" with `forceSticky()`. [Here's a demonstration](https://jsfiddle.net/va41dsrn/). Also see [position sticky polyfill with overflow support](https://stackoverflow.com/a/52420677/924299). – showdev Jul 12 '19 at 03:14

1 Answers1

1

As you already noticed any overflow property between the sticky position and the scroll will break it (explained here: Why is 'position: sticky' not working with Core UI's Bootstrap CSS and here What are `scrolling boxes`?).

One workaround in your case is to move the scroll to another element and hide the default one:

.theproblem {
  overflow-x: hidden;
}
/* Added this */
.columnwrapper {
  height:100vh;
  overflow:auto;
}
body {
  overflow:hidden;
  margin:0;
}
/**/

.column {
  display: inline-block;
  width: 45%;
  vertical-align: top;
}

.column1 {
  border: 1px solid red;
  height: 1000px;
}

.column2 {
  border: 1px solid green;
  position: sticky;
  top: 1px;
}
<div class="theproblem">
  <div class="columnwrapper">
    <div class="column column1">
      This is column 1 (the tall one)
    </div>
    <div class="column column2">
      This is column 2 (the sticky one)
    </div>
  </div>
</div>
Temani Afif
  • 245,468
  • 26
  • 309
  • 415
  • Hmm...interesting! Seems forcing a height on the wrapper to make that the scrolling item is key. Let me play with this a bit. Thanks! – DA. Jul 12 '19 at 13:07
  • I think this is the best we can do with just CSS. Alas, it's still limiting somewhat in that you have to force a height which isn't going to work in a lot of situations (including ours). But it's a good solution in some cases, I think! – DA. Jul 12 '19 at 15:19
  • 1
    @DA. I think there are no more ways too. The specification will probably change as this feature is still new and we will have more flexibility (let's hope so ...) – Temani Afif Jul 12 '19 at 15:39