Search code examples
iosscrollsafaripositioning

iOS Safari issue - Element becomes invisible while scrolling when changing position absolute to fixed


I want to use an element on the page as the title of the following content, but when the user is scrolling into the content this title-element should be fixed at the header. Similar to the ABC-captions in the iOS music-app.

See here: https://jsfiddle.net/1e7ync4w/

HTML

<div>
  <div class="top">
  Test
  </div>
  <div class="content">
    <div class="scroller">

    </div>

    Test
  </div>
</div>

CSS

.top {
  background-color: yellow;

  height: 300px;
}

.content {
  position: relative;

  height: 600px;

  background-color: green;
}

.scroller {
  position: absolute;

  width: 100%;
  height: 10px;

  top: 0;
  left: 0;

  background-color: blue;
}

.scroller.fixed {
  position: fixed;
}

JS

$(document).ready(function() {
    $(window).on('scroll touchmove', function() {
      $('.scroller').removeClass('fixed');


    var scrollTop = $(window).scrollTop();
    var scrollerOffsetTop = $('.scroller').offset().top;

    if(scrollerOffsetTop <= scrollTop) {
                $('.scroller').addClass('fixed');
    }
});
  });

The problem is that the iOS safari seems to have a bug with changing elements to fixed (via JavaScript) while scrolling. As soon as the user scrolls into the content, the title-element becomes invisible but shows after releasing the finger from the display (scroll-end).

I only tested this on the iOS 9.3.2 safari but I think this issue is older.


Solution

  • I found a solution for this problem. It's a little bit hacky but the only workaround I found for this iOS-bug.

    The GPU of the browser needs to be "activated" for updating the according element. This can be achieved by setting a transform: translate-style via JS as soon as the positioning jumped to fixed.

    The code of the example would look like this:

    $(document).ready(function () {
        $(window).on('scroll touchmove', function () {
            $('.scroller').removeClass('fixed');
    
    
            var scrollTop = $(window).scrollTop();
            var scrollerOffsetTop = $('.scroller').offset().top;
    
            if (scrollerOffsetTop <= scrollTop) {
                $('.scroller').addClass('fixed').css({
                    'transform': 'translate3d(0px,0px,0px)',
                    '-moz-transform': 'translate3d(0px,0px,0px)',
                    '-ms-transform': 'translate3d(0px,0px,0px)',
                    '-o-transform': 'translate3d(0px,0px,0px)',
                    '-webkit-transform': 'translate3d(0px,0px,0px)'
                });
            }
        });
    });