Ok! First I'd like to apologize as this question wasn't possible to be answered without rendering the HTML. Fortunately, I have found the solution.
TL;DR In this case, no, you need JavaScript. You will need to implement a translateY transform in the element to achieve this. I don't know if the problem is that the parent element has a transform property and it causes this bug or there's something else causing the issue.
Explanation:
I'm currently using a carousel JS library called tiny slider. I'm displaying form elements instead of images, (Building a responsive table; Had issues when I tried using CSS Grids). So far, so good. The problem started when I wanted to set sticky the date headers.
I went with the modern approach of setting position:sticky, but that didn't work. The elements would get clogged in a certain position and it wouldn't move or stick. I started researching online (which ended up asking this same question), and the HTML itself. I did find that there were many parent <div>s that were created by tiny-slider. My theory was that it was getting attached to one of those parents.  
Therefore, I decided to try the old tactic of combining position:fixed with a scroll event. But, that didn't work. Going back online and Google-Fuing a bit, there seems to be an old bug [1] [2] [3] that whenever a translate is applied to one of the parents an out-of-root container is created and position:fixed doesn't work as expected. 
I have a hunch that this may be one of the reasons why sticky didn't work, but according to this answer, it doesn't seem like it.
I kept thinking for a while, and resorted to use a transform CSS property with translateY. I made a small experiment in the browser, and it worked! 
Hence, I ended up implementing the scroll eventListener and listening to the header's parent's position, and applying getBoundingClientRect() to get the offset. If I had applied it to the element itself, it would have given me the translated position which I applied through CSS. 
I was skeptical that this could be a performance bottleneck for mobile browsers. Therefore, I checked that the transform function was called inside a requestAnimationFrame and it had applied a will-change property in the CSS stylesheet.  
I ran the code with a 4x CPU Slowdown in Google Chrome, and had good results . 
Here's the resulting function I have (Where elemsToFixed are all the <header> elements, and threshold is the top offset so it doesn't conflict with the navbar):
export function fixedHeaderScroll(elemsToFixed: HTMLHeadingElement[], threshold: number) {
  if (!elemsToFixed || elemsToFixed.length === 0) {
    console.error("elemsToFixed can't be null or empty");
    return;
  }
  console.log('Total elems', elemsToFixed.length);
  // We assume that all of the elements are on the same height.
  const firstEl = elemsToFixed[0];
  let propSet = false;
  window.addEventListener('scroll', (e) => {
    window.requestAnimationFrame(() => {
      const top = firstEl.parentElement!.getBoundingClientRect().top;
      if (top > threshold) {
        if (!propSet) return;
        propSet = false;
        setElemsFixed(elemsToFixed, top, threshold, false);
        return;
      }
      propSet = true;
      setElemsFixed(elemsToFixed, top, threshold);
    });
  });
}
function setElemsFixed(elemsToFixed: HTMLHeadingElement[], top: number,
                       threshold: number, setFixed = true) {
  console.log('SetElemsFixed is', setFixed);
  elemsToFixed.forEach((elem) => {
    if (!setFixed) {
      elem.removeAttribute('style');
      return;
    }
    elem.style.transform = `translateY(${(top * -1)}px)`;
  });
}
The following picture shows a 4x slowdown in the CPU and the calculation of the style (With 26 elements) is about 29.4ms (Which is great!). Using Chrome 70 on Windows and i7 4700MQ processor.
