62

iOS 5 released web designers a new property -webkit-overflow-scrolling:touch that uses the iOS devices hardware accelerator to provide native scrolling for a scrollable div.

When implemented on our site in development it does work but not well. I believe there may be a CSS issue hence I ask here.

The following fiddle will show you it working perfectly

If you pop over to our site in development you will find the same panel under facilities tab but on iOS although the scrolling is perfect the overflowed section is not shown with pictures literarily chopped in two.

http://www.golfbrowser.com/courses/mill-ride/

I have no idea how to fix this http://www.golfbrowser.com/photo.PNG

Devid Farinelli
  • 7,514
  • 9
  • 42
  • 73
Walrus
  • 19,801
  • 35
  • 121
  • 199
  • 1
    I've encountered a similar issue on iOS6 (the page in question worked fine on iOS5). Fixed by applying -webkit-transform: translate3d(0, 0, 0); to the img tags which had been chopped off, working fine now. – codebox Sep 27 '12 at 10:36

8 Answers8

94

As @relluf pointed out, applying 3D transitions on the relative element fixes the bug. However, I investigated it a bit further and it seems that applying -webkit-transform: translateZ(0px) works too (this is what Google does on gmaps map container) and it does not need to be on the relatively positioned element, just the direct descendant of the scrollable element.

So if you don't want to manually keep a list of all the places where the fix is needed, you just might do:

element {
    -webkit-overflow-scrolling: touch;
}

element > * {
    -webkit-transform: translateZ(0px);
}
Devid Farinelli
  • 7,514
  • 9
  • 42
  • 73
spheroid
  • 992
  • 8
  • 2
  • Also for me. The secret is to do the `-webkit-transform` on the items INSIDE the scrolling area. – John Gietzen Sep 22 '12 at 03:30
  • 4
    I feel like `element > *` was buggy. Although it fixed the clipping problem, the scrolling element would flicker while scrolling. I fixed the flickering by applying the hardware acceleration to all elements with: `element *` (no direct child selector). – Pwner Feb 01 '13 at 18:44
  • 1
    this kinda reminds me of the old days of having to put zoom:1 on elements to fix hasLayout issues. :( – bkdraper Jun 04 '13 at 23:55
  • This helped me a lot.. But 1 question i have. I am also scrolling bg image like a parallax scroll effect, i.e. jerky? any help? – Ahsan Khurshid Jun 20 '13 at 07:01
  • are you saying we're repeating history @bkdraper ?! certaintly not... ;) ... something also worth mentioning is GreenSock.com's GSAP animation tool. The address problems like these along w/ some css3 problems that we thought would fix everything (sike). Check it out – Oneezy Apr 04 '14 at 02:56
  • I posted this comment on another thread, but use this solution with care on mobile devices. I saw out of memory errors when trying this blindly (an extra 70 MB of memory usage for a few dozen elements). Instead, I resorted to using this solution but disabling the transform after one second. – mathew Jul 09 '14 at 20:00
  • 3
    this is not a good solution at all, as it will create a lot more rendering layers to the browser and will make much more layer composition work on the GPU! Mobile devices have lower GPU memory and will not support this well. See http://aerotwist.com/blog/on-translate3d-and-layer-creation-hacks/ – Sebastien Lorber Jul 30 '14 at 14:23
  • 3
    This solution is seriously terrible. An incredibly inefficient selector that will spawn tons of GPU rendering layers. – Aaron Oct 08 '14 at 21:02
  • I'm getting the flickering effect also. The element stays in place, but jiggles around when you scroll. How to fix this? – JackKalish Feb 01 '17 at 00:28
  • Another problem is that if you have any elements with `position:fixed` inside a transform, it makes them relative to that transformed element, instead of the viewport. So it's not necessarily safe to do this. Still looking for a better solution. – JW. Sep 26 '18 at 20:46
18

What a bugger they let loose here. Tried all manner of workarounds until I finally found the only property needed by for elements to be properly rendered in a -webkit-overflow-scrolling:touch div: position: static

Relative and absolute positioned elements are always cut off on the boundary, and completely missing (except for empty space) outside of it. If you change the position property dynamically, from static to absolute, only the visible portion of the scrollable div viewport stays rendered, wherever the offset happens to be.

Devid Farinelli
  • 7,514
  • 9
  • 42
  • 73
user1012566
  • 226
  • 1
  • 3
  • 4
    This worked for me, I removed position: relative from some input elements (leaving them as the default position :static) and they render properly throughout the scroll. – Paul Dec 02 '11 at 01:54
6

I have run into this bug as well. I fixed it by applying the following css to parent elements:

-webkit-transform: translate3d(0, 0, 0);

However, I have noticed that that slows down rendering and might select other input elements than wanted when a touched input element is scrolled into the center of the view (by Safari/iOS).

josh3736
  • 139,160
  • 33
  • 216
  • 263
relluf
  • 99
  • 1
  • 2
  • 4
    This worked for me, setting it on the `position: relative` element inside the `-webkit-overflow-scrolling: touch` container. – samy-delux Jan 17 '12 at 10:45
  • Please ignore the part "and might select other input elements than wanted when a touched input element is scrolled into the center of the view". I was mistaken. – relluf Jan 26 '12 at 03:35
3

In iOS, when an element inside an element with -webkit-overflow-scrolling: touch set is positioned absolutely (or fixed) relative to an element outside of the scrolling container, the element is rendered only once and the rendering is not updated as the element is scrolled. Sample HTML:

<div class="relative-to-me">
  <div class="scrollable">
    <div class="absolutely-positioned">
    </div>
  </div>
</div>

If you force a re-render by changing a CSS property (in the inspector for example), you can see that the element's positioning is re-rendered into the correct location. I suspect this is a result of some performance features to optimize scrolling performance.

The solution to this problem is to set will-change: transform on the absolutely (or fixed) positioned element.

.absolutely-positioned {
    will-change: transform;
}
joeyhoer
  • 3,587
  • 1
  • 19
  • 23
2

I deeply investigated this bug, I also created a jsfiddle and submitted it to Apple in a bug report. Please see: iOS5 Images disappear when scrolling with webkit-overflow-scrolling: touch As soon as Apple replies to me, I'll report it on that topic so you can stay up-to-date about this very annoying bug

Community
  • 1
  • 1
lucaferrario
  • 990
  • 9
  • 9
1

The bug still lives in iOS 6. If your issue is related to position: relative, you might solve the issue be setting z-index: 1 temporarily via JS. -webkit-transform: translate(...) did not work with position: relative in my case.

Bernd
  • 1,111
  • 2
  • 9
  • 7
1

I also experienced the problem where overflow scroll with -webkit-overlfow-scrolling set to touch resulted in redraw problems with positioned elements. In my case I had a list where the individual items had relative positioning so that I could use positioning on their child elements. With the above CSS on iOS 5, when the user scrolled hidden content into view, there was a momentary delay before it redrew the screen to review the elements. It was really annoying. Fortunately I discover that if I gave the parent node position relative as well, this was resolved.

Robert
  • 11
  • 1
0

I tried some different solutions, seemed not work perfectly in my case.

Finally I've found a way works fine with jQuery:

Apply -webkit-overflow-scrolling property every time when you touch up.

*At first I Applied Also -webkit-overflow-scrolling:auto when TouchDown, to disable iOS rendering. But it made Page blink. So I dropped it away, then works fine surprisingly!

Check lines below, hope it helps:

<!--  JQuery Functions-->

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script type="text/javascript">

// Apply -webkit-overflow-scrolling in Every TouchEnd
$(document).on('click touchend', function(event) {
    $("#TestDIV").css({"-webkit-overflow-scrolling":"touch"});
});

</script>



<!--  html Elements & Style -->

<div id="TestDIV">
    <div class="Element"></div>
    <div class="Element"></div>
    <div class="Element"></div>
    <div class="Element"></div>
    <div class="Element"></div>
</div>

<style>
#TestDIV{
    white-space: nowrap;
    overflow-x: scroll;
    -webkit-overflow-scrolling:touch;
}

#TestDIV .Element{
    width:300px;
    height:300px;

    margin: 2px;

    background-color: gray;

    display: inline-block;
}
#TestDIV .Element:nth-child(odd){
    background-color: whitesmoke;
}   
</style>
Corxit Sun
  • 618
  • 6
  • 8
  • This helps in my case (text disappearing when typing in a text box) as it causes re-render due to css changes in React setup. However, I had to set it to auto first, then touch. Found out this issue is fixed in iOS 13. – Evan Nov 11 '19 at 03:29