Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scrolling <div> in iOS causes div to blank out

Tags:

html

ios

cordova

I'm trying to handle a long list of <div>s and maintain scroll position in the list after navigating off and coming back. Essentially when a selection made is in the list I capture the listScrollPos and then try to reset it when I'm returning to the page (in Angular - so the list is re-rendered first).

vm.getAlbums = function() {
    albumService.getAlbums()
        .success(function (data) {
            vm.albums = data;                    
            $timeout(function () {                        
                if (albumService.listScrollPos) {
                    $("#MainView").scrollTop(albumService.listScrollPos);
                    albumService.listScrollPos = 0;
                }
            }, 50); // delay required
        })
        .error(function(err) {
            vm.error.error(err.message);
        });
};

The process works fine in all browsers I tested - except on iOS in a WebView (Safari works fine). In other browsers the list displays and the scroll position is moved after the initial render. The pointer resets and all is good.

However, on iOS 8 either in Safari or a Web View in Cordova, the div turns white and shows 'empty'. If I touch the div anywhere it immediately displays at the correct scroll position.

IOW, the DOM appears to be updated and rendered, but the browser is somehow optimizing the scrolled content that was moved under program control.

Is there any way to force the browser to re-render the element after the scroll position was moved programmatically?

like image 695
Rick Strahl Avatar asked Oct 19 '22 08:10

Rick Strahl


1 Answers

Ok, so after a bit more checking the problem is definitely isolated to the iOS WebView - Safari on iOS works fine without any of the following. But a Cordova app or a pinned iOS app exhibits this 'white out' behavior.

The workaround is to explicitly force the DOM to re-render the element using the 'scrollHeight reading trick'.

Here's the code that works:

vm.getAlbums = function() {
    albumService.getAlbums()
        .success(function (data) {
            vm.albums = data;                    
            setTimeout(function () {                        
                if (albumService.listScrollPos) {
                    var el = $("#MainView");
                    el.scrollTop(albumService.listScrollPos);
                    albumService.listScrollPos = 0;
                    $timeout(function() {
                        var t = el[0].scrollHeight;
                    }, 1);
                }
            }, 1); // delay around animation 900
        })
};

Notice the last $timeout() block that simply reads the scrollHeight of the element, which forces the re-render and properly displays the result.

There's a little jumpiness due to the slight rendering delay.

like image 181
Rick Strahl Avatar answered Oct 27 '22 21:10

Rick Strahl