Position sticky with direction rtl not working

Viewed 1986

I have a wrapper div.container inside are div.children. I am setting position:sticky on the first child. I works fine on direction:ltr, however on direction:rtl sticky don't work.

I'm not sure if this is a browser bug or my styles are just wrong. Please note that I don't have access to the html itself, I can only change the css file and no js as possible.

Tested on:

Firefox - Pass ✅
Google Chrome - Fail ❌
Safari - Fail ❌

.container {
    margin: 10px;
    padding: 0;
    border: 1px solid #000;
    overflow-x: scroll;
    overflow-y: hidden;
    width: 500px;
    position: relative;
  white-space: nowrap;
}
.container.ltr { direction: ltr; }
.container.rtl { direction: rtl; }

.children {
  display: inline-block;
    margin: 0;
    padding: 0;
    width: 100px;
    height: 100px;
    border: 1px solid rgba(0,0,0,0.08);
}
.children.sticky {
    position: sticky;
    background: #f30;
    color: #fff;
}

.container.ltr .children.sticky { left: 0; }
.container.rtl .children.sticky { right: 0; }
<div class="container ltr">
  <div class="children sticky">1</div>
  <div class="children">2</div>
  <div class="children">3</div>
  <div class="children">4</div>
  <div class="children">5</div>
  <div class="children">6</div>
  <div class="children">7</div>
  <div class="children">8</div>
  <div class="children">9</div>
  <div class="children">10</div>
</div>

<div class="container rtl">
  <div class="children sticky">1</div>
  <div class="children">2</div>
  <div class="children">3</div>
  <div class="children">4</div>
  <div class="children">5</div>
  <div class="children">6</div>
  <div class="children">7</div>
  <div class="children">8</div>
  <div class="children">9</div>
  <div class="children">10</div>
</div>

Chromium Bug Report
https://bugs.chromium.org/p/chromium/issues/detail?id=1140374

3 Answers

position: sticky has got certain set of limitations in it's behaviour, please refer to https://www.designcise.com/web/tutorial/how-to-fix-issues-with-css-position-sticky-not-working

Please check if position: fixed serves your purpose.

.container {
    margin: 10px;
    padding: 0;
    border: 1px solid #000;
    overflow-x: scroll;
    overflow-y: hidden;
    width: 500px;
    position: relative;
  white-space: nowrap;
}
.container.ltr { direction: ltr; }
.container.rtl { direction: rtl; }

.children {
  display: inline-block;
    margin: 0;
    padding: 0;
    width: 100px;
    height: 100px;
    border: 1px solid rgba(0,0,0,0.08);
}
.container.ltr .children:nth-child(2){
  margin-left: 102px;
}
.container.rtl .children:nth-child(2){
  margin-right: 102px;
}
.children.sticky {
    /* position: sticky; */
  position :fixed;
    background: #f30;
    color: #fff;
}

/*.container.ltr .children.sticky { left: 0; }
.container.rtl .children.sticky { right: 0; } */
<div class="container ltr">
      <div class="children sticky">1</div>
      <div class="children">2</div>
      <div class="children">3</div>
      <div class="children">4</div>
      <div class="children">5</div>
      <div class="children">6</div>
      <div class="children">7</div>
      <div class="children">8</div>
      <div class="children">9</div>
      <div class="children">10</div>
    </div>

    <div class="container rtl">
      <div class="children sticky">1</div>
      <div class="children">2</div>
      <div class="children">3</div>
      <div class="children">4</div>
      <div class="children">5</div>
      <div class="children">6</div>
      <div class="children">7</div>
      <div class="children">8</div>
      <div class="children">9</div>
      <div class="children">10</div>
    </div>

am also having the same issue but with table scroll with a sticky header above it & so as a temp solution for now, we can us a bit of js to reset the scroll to start from the right as expected.

so lets say we have a div that have a scrollable table and a header that should be sticky when we scroll right/left

<div class="scrollable" data-scroll-reset>
    <div class="sticky">
        this should remain still no matter how we scroll to left/right
    </div>

    <table class="rtl">
        <thead>...</thead>
        <tbody>...</tbody>
    </table>
</div>

<style>
    .scrollable {
        overflow-x: scroll;
    }

    .sticky {
        left: 0;
        right: 0;
        z-index: 1;
        position: sticky;
    }

    .rtl {
        direction: rtl;
    }
</style>

<script>
window.addEventListener('load', () => {
    document.querySelectorAll('[data-scroll-reset]').forEach((e) => {
        e.scrollLeft = 10000
    })
})
</script>

both data-scroll-reset & rtl should be added on condition, otherwise it will mess the scrolling when the direction is changed to ltr.

I bumped into this same issue. Managed to find a workaround by using an extra container div, which seems to work fine on Chrome (v93), but still fails in Safari (v14.1.2), somehow it moves the sticky element to the left (???)

.container {
  margin: 10px;
  border: 1px solid #000;
  overflow: auto;
  width: 500px;
  white-space: nowrap;
}

.container.ltr { 
  direction: ltr;
}

.container.rtl {
  direction: rtl;
}

.inner {
  display: inline-block;
}

.children {
  display: inline-block;
  width: 100px;
  height: 100px;
  border: 1px solid rgba(0,0,0,0.08);
}

.children.sticky {
  position: sticky;
  background: #f30;
  color: #fff;
}

.container.ltr .children.sticky { 
  left: 0;
}

.container.rtl .children.sticky {
  right: 0;
}
<div class="container ltr">
  <div class="children sticky">1</div>
  <div class="children">2</div>
  <div class="children">3</div>
  <div class="children">4</div>
  <div class="children">5</div>
  <div class="children">6</div>
  <div class="children">7</div>
  <div class="children">8</div>
  <div class="children">9</div>
  <div class="children">10</div>
</div>

<div class="container rtl">
  <div class="inner">
    <div class="children sticky">1</div>
    <div class="children">2</div>
    <div class="children">3</div>
    <div class="children">4</div>
    <div class="children">5</div>
    <div class="children">6</div>
    <div class="children">7</div>
    <div class="children">8</div>
    <div class="children">9</div>
    <div class="children">10</div>
  </div>
</div>

In my real use case there are more sticky elements (like the text in each children box), which are working somehow in Safari as well, but could not replicate that with a simple example. I also have a sticky sidebar, which has the same behavior as in the example above.

Related