'overflow-anchor doesn't work for horizontal scrolling

I would like to build an infinite horizontal scroll that scrolls in both directions - left and right. As user scrolls to the left, new content is prepended to the scrollable element (think scrolling through a schedule history, for example). As they scroll to the right, content is appended.

I have learned that browsers anchor content when scrolling up and down which is fantastic, exactly what I'd expect. The effect of that is that prepending content to the scrolled element anchors user to their current, logical position and the content doesn't "jump".

But the anchoring doesn't seem to work when scrolling left or right. The behaviour is as if I set overflow-anchor: none. What can I do to make it work as well as when scrolling up?

let topCounter = 0;
document.querySelector('.scrollable-top').scrollTo({ top: 100 });
document.querySelector('.scrollable-top').onscroll = (event) => {
  if (event.target.scrollTop < 100) {
    let box = document.createElement('div');
    box.className = 'content-box';
    box.textContent = `${topCounter--}`;
    document.querySelector('.scrollable-top').prepend(box);
  }
};

let leftCounter = 0;
document.querySelector('.scrollable-left').scrollTo({ left: 100 });
document.querySelector('.scrollable-left').onscroll = (event) => {
  if (event.target.scrollLeft < 100) {
    let box = document.createElement('div');
    box.className = 'content-box';
    box.textContent = `${leftCounter--}`;
    document.querySelector('.scrollable-left').prepend(box);
  }
};
.scrollable-top {
  width: 200px;
  height: 250px;
  overflow-y: auto;
  border: solid 1px black;
}

.scrollable-left {
  display: flex;
  width: 250px;
  overflow-x: auto;
  border: solid 1px black;
}

.content-box {
  flex: 1 0 auto;
  height: 150px;
  width: 150px;
  border: solid 1px red;
  display: flex;
  justify-content: center;
  align-items: center;
}
<div class="scrollable-top">
  <div class="content-box">1</div>
  <div class="content-box">2</div>
  <div class="content-box">3</div>
</div>

<div class="scrollable-left">
  <div class="content-box">1</div>
  <div class="content-box">2</div>
  <div class="content-box">3</div>
</div>


Solution 1:[1]

Scroll the horizontal container to the right by 150 using scrollBy(150, 0):

let topCounter = 0;
document.querySelector('.scrollable-top').scrollTo({ top: 100 });
document.querySelector('.scrollable-top').onscroll = (event) => {
  if (event.target.scrollTop < 100) {
    let box = document.createElement('div');
    box.className = 'content-box';
    box.textContent = `${topCounter--}`;
    document.querySelector('.scrollable-top').prepend(box);
  }
};

let leftCounter = 0;
document.querySelector('.scrollable-left').scrollTo({ left: 100 });
document.querySelector('.scrollable-left').onscroll = (event) => {
  if (event.target.scrollLeft < 100) {
    let box = document.createElement('div');
    box.className = 'content-box';
    box.textContent = `${leftCounter--}`;
    document.querySelector('.scrollable-left').prepend(box);
    
    // solution ------------------
    event.target.scrollBy(150, 0);
  }
};
.scrollable-top {
  width: 200px;
  height: 250px;
  overflow-y: auto;
  border: solid 1px black;
  display: inline-block;    
  float:left;
}

.scrollable-left {
  display: flex;
  width: 250px;
  overflow-x: auto;
  border: solid 1px black;
  float:right;
}

.content-box {
  flex: 1 0 auto;
  height: 150px;
  width: 150px;
  border: solid 1px red;
  display: flex;
  justify-content: center;
  align-items: center;
}
<div class="scrollable-top">
  <div class="content-box">1</div>
  <div class="content-box">2</div>
  <div class="content-box">3</div>
</div>

<div class="scrollable-left">
  <div class="content-box">1</div>
  <div class="content-box">2</div>
  <div class="content-box">3</div>
</div>

As per the specs, following is the intent behind such anchoring:

Changes in DOM elements above the visible region of a scrolling box can result in the page moving while the user is in the middle of consuming the content. This spec proposes a mechanism to mitigate this jarring user experience by keeping track of the position of an anchor node and adjusting the scroll offset accordingly.
This spec also proposes an API for web developers to opt-out of this behavior.

Since no page loads horizontally, I think they didn't implement this for horizontal scrollbars. Also, apart from above use case it makes no sense to implement this behavior.

Note: Safari doesn't implement the overflow-anchor behavior. So, your code for vertical scroll fails in Safari.
I've tried my code, for horizontal scrolling, on Safari and it works. So incase you want to implement infinite vertical scroll, and want to support all the browsers, then you'll have to optout of overflow-anchor behavior and use scrollBy(x,y) to do it manually. :(

Solution 2:[2]

I tried to fix your code and got this option

let leftCounter = -2;
let rightCounter = 2;
document.querySelector('.scrollable-left').scrollTo({ left: 100 });
document.querySelector('.scrollable-left').onscroll = (event) => {
  if (event.target.scrollLeft < 100) {
    let box = document.createElement('div');
    box.className = 'content-box';
    box.textContent = `${leftCounter--}`;
    document.querySelector('.scrollable-left').prepend(box);
    event.target.scrollLeft += 250
  }
  if ((event.target.scrollWidth - event.target.scrollLeft - 250) < 100) {
    let box = document.createElement('div');
    box.className = 'content-box';
    box.textContent = `${rightCounter++}`;
    document.querySelector('.scrollable-left').append(box);
  }
};
.scrollable-top {
  width: 200px;
  height: 250px;
  overflow-y: auto;
  border: solid 1px black;
}

.scrollable-left {
  display: flex;
  width: 250px;
  overflow-x: auto;
  border: solid 1px black;
}

.content-box {
  flex: 1 0 auto;
  height: 150px;
  width: 150px;
  border: solid 1px red;
  display: flex;
  justify-content: center;
  align-items: center;
}
<div class="scrollable-left">
  <div class="content-box">-1</div>
  <div class="content-box">0</div>
  <div class="content-box">1</div>
</div>

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Hat