Css scroll-snap bug iOS 10
Asked Answered
C

2

45

I noticed a strange bug in iOS 10 with the CSS scroll-snap properties.

Here's my css:

#springBoard{
    height: 100%;
    width: 100%;
    font-size: 0px;
    white-space: nowrap;
    overflow: scroll;
    -webkit-overflow-scrolling: touch;
    -webkit-scroll-snap-type: mandatory;
    -webkit-scroll-snap-points-x: repeat(100%);
}

section{
    display: inline-block;
    width: 100%;
    height: 100%;
    vertical-align: top;
    font-size: 16px;
}

If I programmatically scroll to a snap-point and then change the content inside the scroll-snap container, the nav snaps back to the first snap-point.

// Programatically scroll the scroll-snap container 
$("#springBoard")[0].scrollLeft = 320

It doesn't seem to be related to the way I trigger the scrolling. All these scrolling methods produce the same result:

$("#springBoard")[0].scrollLeft = 320
$("#springBoard").animate({scrollLeft: 320}, 1)
$("#springBoard > section:eq(1)")[0].scrollIntoView()
window.location.hash = "sectionId"
  1. The bug doesn't happen when scrolling manually (See @maxime's comment below).
  2. It's present since version 10.3.2 of iOS.
  3. Don't know if it's fixed in iOS 11.

I spent a couple of days trying to solve the issue but without success so far.

Here's a stripped-down example of my nav:

Codepen Demo

Does anyone know a way around this stupid bug?

Cervicitis answered 19/7, 2017 at 18:20 Comment(5)
If i navigate and then click on the Change Contentbutton it stays at the same snap point. It is only if i click on the button without having done any scrolling that there is the bug.Pygmy
Have you tried programmatically scrolling the page? window.scrollTo(0, 0); //or some variantBrandwein
Thanks for the suggestion, I tried scrolling the window but it doesn't solve the issue.Cervicitis
bugzilla.mozilla.org/show_bug.cgi?id=1331632 <-- I think this is realatedRozamond
This feature is still so experimental. In Safari on Mac OSX it keeps scrolling the page when you scroll with snapping vertically within an overflow box webkit.org/demos/scroll-snap Chrome does not even support it yet. Better using JS for that as of now.Thornhill
W
1

I created my own HORIZONTAL jquery scroll-snap which gets triggered on page load, window resize, and scroll of the container - this prevents any need for css:

$(".container").scroll(function() {

The following if/else statement is if you plan to change the object's width depending on the width of the page. If not, you can just delete it and set var width = your default width

   var width = 1; //100% - default value / small screen
    if(window.innerWidth >= 993) //large screen
         width = 1/4; //25%
    else if(window.innerWidth >= 601) //medium screen
        width = 1/3; //33.333%

    var containerWidth = $(".container").width();
    var sectionWidth = containerWidth * width; //gets the length of each section

    var currentScroll = $(".container").scrollLeft();
    var farOff = currentScroll % sectionWidth; //determines how far user is from the beginning of the current section
    if(farOff == 0) //just for efficiency
        return;

    clearTimeout($.data(this, 'scrollTimer'));

    $.data(this, 'scrollTimer', setTimeout(function() {
        if(farOff >= sectionWidth/2) //scroll-snaps to next section
            $(".container").animate({
                scrollLeft: (currentScroll + sectionWidth - farOff),
            });
        else //scroll-snaps to previous section
            $(".container").animate({
                scrollLeft: (currentScroll - farOff),
            });
    }, 550));
});

Below is the CSS that goes along with my scroll snap example

div.container{
    overflow-x: scroll;
    -webkit-overflow-scrolling: touch;
    -o-overflow-scrolling: scroll;
    -moz-overflow-scrolling: scroll;
    overflow-y: hidden;
    white-space: nowrap !important;
}
.container section{
    display: inline-block;
    padding: 10px;
    width:100%;
    vertical-align: top;
    margin-bottom: 10px;
}
.container > section > div{
    overflow: initial;
    white-space: normal;
}
@media (min-width: 601px){ /* medium */
    .container section{
        width: 33.33333333%;
    }
}
@media (min-width: 952px){ /* large */
    .container section{
        width: 25%;
    }
}
Whitley answered 27/1, 2018 at 0:32 Comment(0)
B
-2

Please try like this:

$('#springBoard').animate({scrollLeft: $('#springBoard').position().left + 320},1 );
Brendanbrenden answered 14/12, 2017 at 10:27 Comment(2)
Position().left will always return 0. Also, why are you animating the element for 320ms? The 320 in my code refers to the width of an iPhone SE. This makes no sense to me.Cervicitis
Sorry, I was suppose to add that with the position. but it's my mistake. $('#springBoard').animate({scrollLeft: $('#springBoard').position().left + 320}, 1);Brendanbrenden

© 2022 - 2024 — McMap. All rights reserved.